<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>服务器 on 勇气</title><link>https://courages.us/category/%E6%9C%8D%E5%8A%A1%E5%99%A8/</link><description>Recent content in 服务器 on 勇气</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Wed, 12 Apr 2023 21:33:27 +0800</lastBuildDate><atom:link href="https://courages.us/category/%E6%9C%8D%E5%8A%A1%E5%99%A8/index.xml" rel="self" type="application/rss+xml"/><item><title>mTLS 认证</title><link>https://courages.us/mtls-%E8%AE%A4%E8%AF%81/</link><pubDate>Wed, 12 Apr 2023 21:18:30 +0800</pubDate><guid>https://courages.us/mtls-%E8%AE%A4%E8%AF%81/</guid><description>&lt;p&gt;有时候虽然我们部署一个服务到了公网，但只想提供给部分用户而不想其他人（黑客/robot）使用，比如webhook或者跨机房的服务调用。虽然我们可以使用密码/token保护这些服务，但是程序可以被直接扫描到，仍然存在被攻击的风险。而如果把这些服务放在某个认证服务器后面，又存在二次登陆的问题。如何标识目标用户又不影响请求过程？答案是mTLS认证。&lt;br&gt;&#10;TLS认证是当前WEB通信的基石，没有加密的通信无异于裸奔：任何中间人都可以查看/串改通信内容。mTLS认证，亦即双向TLS认证，不但客户端校验服务器证书，服务器亦校验客户端证书，这意味着如果客户端证书不在服务器的信任列表里面，那么客户端也访问不了服务。请求认证过程如下&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2023/04/how_mtls_works-what_is_mutual_tls.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="654px" data-flex-grow="272" height="110" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2023/04/how_mtls_works-what_is_mutual_tls-300x110.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;mTLS可以用来保护私有服务，加强通信过程，减少服务器攻击。由于客户端也需要提供证书，证书里面可以携带用户或者设备信息，可以识别仅授信用户，才授权访问 。由于服务器需要校验客户端信息，所以未提供有效证书用户不能访问，就算盗取了用户的密码/token也不可以。因为双方都互相校验证书，所以也可以抵抗中间人攻击。这样子我们便可以公开服务，但又限制某些用户使用了。&lt;br&gt;&#10;mTLS认证有别于应用程序认证。mTLS仅涉及证书校验，在网关出就可以进行，不需要涉及应用程序逻辑/数据库。mTLS也不依赖于请求头/请求体里面的内容，所以不会影响已有程序。&lt;br&gt;&#10;mTLS认证限制某些用户/设备访问，也有别于传统VPN网络。VPN总是要求服务端/客户端先建立连接，才能在同一内网内访问。一旦连接建立，便可以访问所有服务。而采用mTLS认证，则每一个服务都可以使用不同的客户端证书，限制不同的用户访问。零信任（ZeroTrust）亦建立在mTLS之上，即对每个请求都做双向认证。&lt;br&gt;&#10;mTLS并不是什么新鲜事物，许多互联网软件都支持，比如浏览器、SSH，SSH采用私钥登陆的过程，即双向认证：客户端先将自己的公钥上传至服务器，建立连接时，客户端询问是否信任服务器，服务器亦校验客户端。Git使用SSH key登陆也是类似双向认证。开发者调用Google云服务，除了app认证信息，也是需要双向认证的。有些互联网公司也采用双向认证来保护自己的应用，比如支付功能，甚至是所有页面-只允许自己的APP查看，其他免谈。&lt;br&gt;&#10;Nginx早已支持mTLS认证，除了服务器本身的证书，还需要配置客户端证书或其签发root CA证书。关于服务器证书获取之前已介绍&lt;a class="link" href="https://courages.us/lets-encrypt/" target="_blank" rel="noopener"&#10; &gt;基于DNS自动获取证书&lt;/a&gt;了，同样的方法也可以用来生成客户端证书，比如基于用户id来生成不同域名username.id.example.com的证书给客户端使用。这里介绍另外一种基于&lt;a class="link" href="https://github.com/go-acme/lego" target="_blank" rel="noopener"&#10; &gt;LEGO ACME&lt;/a&gt;在本地生成客户端证书的方法。&lt;br&gt;&#10;首先安装lego程序，如果有golang环境直接就好了，或者下载对应平台的&lt;a class="link" href="https://github.com/go-acme/lego/releases" target="_blank" rel="noopener"&#10; &gt;程序&lt;/a&gt;。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ go install github.com/go-acme/lego/v4/cmd/lego@latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后就可以基于&lt;a class="link" href="https://go-acme.github.io/lego/dns/" target="_blank" rel="noopener"&#10; &gt;DNS厂商&lt;/a&gt;来生成证书，这里以腾讯云DNS，注意它的APP Key是不同于DNSPod的。如果网络不加，建议延长TIMEOUT时间。这里一并生成浏览器/系统可用的PKCS12文件(.pfx)&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ TENCENTCLOUD_SECRET_ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;*** TENCENTCLOUD_PROPAGATION_TIMEOUT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;120&lt;/span&gt; TENCENTCLOUD_POLLING_INTERVAL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TENCENTCLOUD_SECRET_KEY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;***&lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lego --email username@exmaple.com --pem --pfx --pfx.pass *** --cert.timeout &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt; --dns tencentcloud --domains user1.idt.exmaple.com run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:46 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Obtaining bundled SAN certificate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/217627103547&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Could not find solver &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: tls-alpn-01&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Could not find solver &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: http-01&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: use dns-01 solver&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Preparing to solve DNS-01&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:50 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Trying to solve DNS-01&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:50 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Checking DNS record propagation using &lt;span style="color:#f92672"&gt;[&lt;/span&gt;127.0.0.53:53&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:55 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Wait &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; propagation &lt;span style="color:#f92672"&gt;[&lt;/span&gt;timeout: 2m0s, interval: 5s&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:55 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:01 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:06 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:11 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:17 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:22 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:35 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The server validated our request&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:35 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Cleaning DNS-01 challenge&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:37 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Validations succeeded; requesting certificates&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:39 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Server responded with a certificate.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -la .lego/certificates&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwx------ &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwx------ &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 10:58 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;5341&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;3751&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.issuer.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;244&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;227&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;5568&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;2992&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.pfx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于这个证书的CA是Let’s Encrypt的，而Let’s Encrypt本身的证书又是Internet Security Research Group签发。而当Nginx配置ssl_client_certificate CA证书时只能是Root CA，也就是ISRG的证书，而不是中间厂商的证书，也就是不能用Let’s Encrypt的CA证书。ISRG的证书可以从浏览器导出或者网上&lt;a class="link" href="http://www.certificate.fyicenter.com/11138_ISRG_Root_X1_Certificate-79B459E67BB6E5E40173800888C81A58F6E99B6E.html" target="_blank" rel="noopener"&#10; &gt;下载&lt;/a&gt;，然后保存到服务器上&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mv isrg_root.crt /etc/nginx/certs/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ chomd &lt;span style="color:#ae81ff"&gt;400&lt;/span&gt; etc/nginx/certs/isrg_root.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nginx配置如下，可以将日志级别设置为debug,调试/观察认证&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/nginx/conf.d/site-available/100-mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name mtls.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;301&lt;/span&gt; https://$host$request_uri;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt; ssl;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name mtls.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_client_certificate /etc/nginx/conf.d/certs/isrg_root.crt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_verify_client on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_verify_depth 2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_session_cache builtin:1000 shared:SSL:10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_prefer_server_ciphers on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# error_log /var/log/nginx/error.log debug;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /var/www/mtls.example.com/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index index.html index.htm;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error_page &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;502&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;503&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;504&lt;/span&gt; /50x.html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /50x.html &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /usr/share/nginx/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用curl测试一下，提示需要客户端证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl https://mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;title&amp;gt;400 No required SSL certificate was sent&amp;lt;/title&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;body bgcolor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;white&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;center&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;h1&amp;gt;400 Bad Request&amp;lt;/h1&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/center&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;center&amp;gt;No required SSL certificate was sent&amp;lt;/center&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;hr&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;center&amp;gt;nginx/1.14.0&amp;lt;/center&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当带上证书的时候就可以了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl --cert user1.idt.exmaple.com.crt --key user1.idt.exmaple.com.key https://mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;title&amp;gt;Welcome to mtls.example.com!&amp;lt;/title&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;h1&amp;gt;Success! The mtls server is working!&amp;lt;/h1&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用浏览器访问目标网站需要安装.pfx文件，否则也会报错，禁止访问。通常Windows/Mac双击.pfx文件即可自动安，也可以通过浏览器配置来安装。使用Chrome需要在从菜单设置-&amp;gt;隐私设置和安全性-&amp;gt;安全-&amp;gt;管理设备证书-&amp;gt;个人-&amp;gt;导入。使用Firefox则是从从菜单设置-&amp;gt;隐私与安全-&amp;gt;安全-&amp;gt;查看证书-&amp;gt;您的证书-&amp;gt;导入。iOS和Android可以通过邮件的方式将.pfx文件传输到手机上，点击.pfx文件按照系统提示安装即可。最后使用浏览器打开https://mtls.example.com，会提示使用刚才配置好的证书，选择即可。&lt;br&gt;&#10;上面Nginx配置的是公共CA的根证书（isrg_root.crt），这意味着所有该CA签发的证书都将可以访问https://mtls.example.com，这有点太开放了。如果我们自己生成Root CA证书，便可以做进一步的控制。&lt;br&gt;&#10;首先生成Root CA证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl genrsa -des3 -out ca.key &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter PEM pass phrase:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Verifying - Enter PEM pass phrase:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl req -new -x509 -days &lt;span style="color:#ae81ff"&gt;3650&lt;/span&gt; -key ca.key -out ca.crt39:06&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter pass phrase &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ca.key:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You are about to be asked to enter information that will be incorporated&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;into your certificate request.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What you are about to enter is what is called a Distinguished Name or a DN.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There are quite a few fields but you can leave some blank&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;For some fields there will be a default value,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If you enter &lt;span style="color:#e6db74"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;, the field will be left blank.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Country Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; letter code&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;AU&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;State or Province Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;full name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Some-State&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Locality Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, city&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organization Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, company&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Internet Widgits Pty Ltd&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organizational Unit Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, section&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Common Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;e.g. server FQDN or YOUR name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Email Address &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat ca.key &amp;gt; ca.pem &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat ca.crt &amp;gt;&amp;gt; ca.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ca.crt ca.key ca.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后使用CA证书生成客户端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl genrsa -out user1.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter PEM pass phrase:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl req -new -key user1.key -out user1.csr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You are about to be asked to enter information that will be incorporated&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;into your certificate request.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What you are about to enter is what is called a Distinguished Name or a DN.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There are quite a few fields but you can leave some blank&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;For some fields there will be a default value,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If you enter &lt;span style="color:#e6db74"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;, the field will be left blank.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Country Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; letter code&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;AU&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;State or Province Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;full name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Some-State&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Locality Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, city&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organization Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, company&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Internet Widgits Pty Ltd&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organizational Unit Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, section&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Common Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;e.g. server FQDN or YOUR name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Email Address &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Please enter the following &lt;span style="color:#e6db74"&gt;&amp;#39;extra&amp;#39;&lt;/span&gt; attributes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;to be sent with your certificate request&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A challenge password &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;An optional company name &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl x509 -req -days &lt;span style="color:#ae81ff"&gt;365&lt;/span&gt; -in user1.csr -CA ca.crt -CAkey ca.key -set_serial &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; -out user1.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Certificate request self-signature ok&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter pass phrase &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ca.key:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl pkcs12 -export -out user1.pfx -inkey user1.key -in user1.crt -certfile ca.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter Export Password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Verifying - Enter Export Password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后将ca.crt上传至服务器/etc/nginx/certs/下面并配置ssl_client_certificate使用该证书即可。使用curl测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl --cert user1.crt --key user1.key https://mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;title&amp;gt;Welcome to mtls.example.com!&amp;lt;/title&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;h1&amp;gt;Success! The mtls server is working!&amp;lt;/h1&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同样可以成功访问。不过刚才生成的.pfx文件只有Firefox可以导入使用，其他系统/浏览器不可以，那么可以从Firefox中重新备份导出该文件，Chrome/其他系统就可以使用了。或者重新转换一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl pkcs12 -in user1.pfx -out user1.pem -nodes &lt;span style="color:#75715e"&gt;#pfx证书转换为x.509格式的pem证书&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl pkcs12 -in user1.pfx -nocerts -nodes -out user1.key &lt;span style="color:#75715e"&gt;#pfx证书中提取密钥对&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl rsa -in user1.key -out user1_private.key &lt;span style="color:#75715e"&gt;#密钥对提取私钥&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl pkcs12 -export -in user1.pem -inkey user1_private.key -out user1.pfx &lt;span style="color:#75715e"&gt;#使用x.509+私钥转换为win10可用的pfx证书&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用自定义CA可以有效控制证书的签发，也可以免CA直接签发客户端证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl req -x509 -nodes -days &lt;span style="color:#ae81ff"&gt;9999&lt;/span&gt; -newkey rsa:2048 -keyout user2.key -out user2.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;..+...+...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You are about to be asked to enter information that will be incorporated&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;into your certificate request.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What you are about to enter is what is called a Distinguished Name or a DN.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There are quite a few fields but you can leave some blank&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;For some fields there will be a default value,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If you enter &lt;span style="color:#e6db74"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;, the field will be left blank.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Country Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; letter code&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;AU&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;State or Province Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;full name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Some-State&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Locality Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, city&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organization Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, company&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Internet Widgits Pty Ltd&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organizational Unit Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, section&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Common Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;e.g. server FQDN or YOUR name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Email Address &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;无CA签名的证书，就直接将user2.crt上传至服务器/etc/nginx/certs/下面并配置ssl_client_certificate使用该证书即可。如果生成了多个，就合并成一个上传服务器就好了。使用curl测试一下，也是可以的&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl --cert user2.crt --key user2.key https://mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;title&amp;gt;Welcome to mtls.example.com!&amp;lt;/title&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;h1&amp;gt;Success! The mtls server is working!&amp;lt;/h1&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nginx还支持将客户端证书及CA的DN传递给后端程序，再配合访问控制，便可以精细控制用户访问了。Nginx配置如下，注意这里ssl_verify_client是optional,认证失败不再返回400而是403&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/nginx/conf.d/site-available/100-mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt; ssl;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name mtls.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate /etc/letsencrypt/live/example.comfullchain.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_client_certificate /etc/nginx/conf.d/certs/ca.crt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_verify_client optional;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_verify_depth 2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_session_cache builtin:1000 shared:SSL:10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_prefer_server_ciphers on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# error_log /var/log/nginx/error.log debug;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# if ($ssl_client_i_dn != &amp;#34;/C=EX/CN=Client/emailAddress=user1@example.com&amp;#34;) {&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# return 403;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# }&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;$ssl_client_verify !&lt;span style="color:#f92672"&gt;=&lt;/span&gt; SUCCESS&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; 403; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header SSL_Client_Issuer $ssl_client_i_dn;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header SSL_Client $ssl_client_s_dn;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header SSL_Client_Verify $ssl_client_verify;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:3000/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error_page &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;502&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;503&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;504&lt;/span&gt; /50x.html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /50x.html &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /usr/share/nginx/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;NodeJS代码如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;express&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;express&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;port&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;host&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { };&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;express&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;) =&amp;gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;status&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;json&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`Hello &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ssl_client&amp;#34;&lt;/span&gt;)&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, your certificate was issued by &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;SSL_Client_Issuer&amp;#34;&lt;/span&gt;)&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;!`&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;listen&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;port&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;host&lt;/span&gt;, () =&amp;gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;listening&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用curl测试一下便会输出客户端DN。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ curl --cert user1.crt --key user1.key https://mtls.example.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Hello emailAddress=user1@example,CN=exmaple,OU=server,C=exmaple, your certificate was issued by emailAddress=user1@example,CN=exmaple,OU=user1,C=exmaple!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;事实上不仅Nginx支持设置客户端认证，&lt;a class="link" href="https://github.com/Kong/kong" target="_blank" rel="noopener"&#10; &gt;Kong网关&lt;/a&gt;，云原生应用传输&lt;a class="link" href="https://github.com/traefik/traefik" target="_blank" rel="noopener"&#10; &gt;traefik&lt;/a&gt;等也早已支持，编程语言层面更是支持开发mTLS应用了。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/" target="_blank" rel="noopener"&#10; &gt;What is mutual TLS (mTLS)?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dapenti.com/blog/index.asp" target="_blank" rel="noopener"&#10; &gt;Mutual authentication&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/haoel/mTLS" target="_blank" rel="noopener"&#10; &gt;mTLS Golang Example&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://datacadamia.com/web/server/nginx/client_authentication" target="_blank" rel="noopener"&#10; &gt;How to configure certification based client authentication with Nginx ?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://dev.to/darshitpp/how-to-implement-two-way-ssl-with-nginx-2g39" target="_blank" rel="noopener"&#10; &gt;How To Implement Two Way SSL With Nginx&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/pandashavenobugs/mTLS-with-node-blogpost" target="_blank" rel="noopener"&#10; &gt;mTLS with node&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://medium.com/geekculture/mtls-with-nginx-and-nodejs-e3d0980ed950" target="_blank" rel="noopener"&#10; &gt;mTLS with NGINX and NodeJS&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://go-acme.github.io/lego/" target="_blank" rel="noopener"&#10; &gt;LEGO&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.infinisign.com/faq/firefox-pfx-import-windows10-error-password" target="_blank" rel="noopener"&#10; &gt;Firefox导出PFX证书在Win10导入提示密码错误&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stackoverflow.com/questions/8431528/nginx-ssl-certificate-authentication-signed-by-intermediate-ca-chain" target="_blank" rel="noopener"&#10; &gt;NGinx SSL certificate authentication signed by intermediate CA (chain)&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>即时通信IRC服务Oragono</title><link>https://courages.us/%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1irc%E6%9C%8D%E5%8A%A1oragono/</link><pubDate>Wed, 18 Nov 2020 15:19:05 +0800</pubDate><guid>https://courages.us/%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1irc%E6%9C%8D%E5%8A%A1oragono/</guid><description>&lt;p&gt;前一篇讲了&lt;a class="link" href="https://courages.us/%e5%8d%b3%e6%97%b6%e9%80%9a%e4%bf%a1xmpp%e6%9c%8d%e5%8a%a1%e5%99%a8ejabberd-openfire/" target="_blank" rel="noopener"&#10; &gt;XMPP通信&lt;/a&gt;，还有一种比它还早的协议&lt;a class="link" href="https://zh.wikipedia.org/wiki/IRC" target="_blank" rel="noopener"&#10; &gt;IRC（Internet Relay Chat）&lt;/a&gt;，是一种简单的文本聊天协议，支持一对一聊天和群聊（频道）。通常IRC聊天只需要昵称而不需要密码（也可以使用密码），这与XMML不同，使得它可以作为公开的聊天频道，比如游戏直播平台Twitch就使用类似的功能来实现聊天。IRC同样有许多服务端，比如&lt;a class="link" href="https://www.inspircd.org/" target="_blank" rel="noopener"&#10; &gt;InspIRCd&lt;/a&gt;和客户端软件，比如&lt;a class="link" href="https://irssi.org/" target="_blank" rel="noopener"&#10; &gt;Irssi&lt;/a&gt;，也可以直接连接公开的IRC服务器，比如&lt;a class="link" href="https://freenode.net/" target="_blank" rel="noopener"&#10; &gt;Freenode&lt;/a&gt;。事实上IRC协议非常简单，只要能对相应的&lt;a class="link" href="https://ircv3.net/irc/" target="_blank" rel="noopener"&#10; &gt;命令&lt;/a&gt;作出响应就可以在各个客户端之间通信，因此有许多不同编程语言的服务端/客户端实现。&lt;a class="link" href="https://github.com/oragono/oragono" target="_blank" rel="noopener"&#10; &gt;Oragono&lt;/a&gt;便是IRC 服务器的Golang实现，支持&lt;a class="link" href="https://ircv3.net/" target="_blank" rel="noopener"&#10; &gt;IRCv3&lt;/a&gt;，支持SASL/LDAP认证，支持服务端保存消息历史记录。&lt;br&gt;&#10;Oragono运行很简单，克隆代码，编辑配置文件就可以了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHANGELOG.md     README           default.yaml     docs             languages        oragono          oragono.motd     traditional.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 cp default.yaml ircd.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 ./oragono mkcerts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020/11/11 12:01:04 making self-signed certificates&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020/11/11 12:01:04  making cert &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; :6697 listener&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020/11/11 12:01:04   Certificate created at fullchain.pem : privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHANGELOG.md     README           default.yaml     docs             fullchain.pem    ircd.yaml        languages        oragono          oragono.motd     privkey.pem      traditional.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 ./oragono run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.320Z : info : server : oragono-2.4.0 starting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.320Z : info : server : Using config file : ircd.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.320Z : info : server : Using datastore : ircd.db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.344Z : info : server : Proxied IPs will be accepted from : localhost&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : listeners : now listening on &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::1&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:6667, tls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tlsproxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, websocket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : listeners : now listening on :6697, tls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true, tlsproxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, websocket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : listeners : now listening on :8097, tls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true, tlsproxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, websocket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : listeners : now listening on 127.0.0.1:6667, tls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tlsproxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, websocket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : server : Server running&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:38.386Z : info : connect-ip : Client connecting: real IP 192.168.33.1, proxied IP &amp;lt;nil&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:38.439Z : info : accounts : client : * : logged into account : kiwi-n30&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:38.442Z : info : connect : Client connected &lt;span style="color:#f92672"&gt;[&lt;/span&gt;kiwi-n30&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;u:~u&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;r:https://kiwiirc.com/&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:40.955Z : info : connect-ip : Client connecting: real IP 192.168.33.1, proxied IP &amp;lt;nil&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:40.963Z : info : connect : Client connected &lt;span style="color:#f92672"&gt;[&lt;/span&gt;kiwi-n28&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;u:~u&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;r:https://kiwiirc.com/&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:56.198Z : info : connect-ip : Client connecting: real IP 192.168.33.1, proxied IP &amp;lt;nil&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:56.209Z : info : connect : Client connected &lt;span style="color:#f92672"&gt;[&lt;/span&gt;kiwi-n29&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;u:~u&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;r:https://kiwiirc.com/&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑ircd.yml，设置管理密码，启用一下WebSocket，保存历史消息到MySQL。opers/admin管理密码在认证管理员的时候使用的，可以使用命令oragono genpasswd生成。ircd.db用来保存注册用户，使用的并不是SQLite，而是Golang实现的一个嵌入式的内存Key/Value存储&lt;a class="link" href="https://github.com/tidwall/buntdb" target="_blank" rel="noopener"&#10; &gt;BuntDB&lt;/a&gt;，可以持久化到硬盘。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# network configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;network&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# name of the network&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;OragonoTest&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# server configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;server&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# server name&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;oragono.test&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# addresses to listen on&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;listeners&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# The standard plaintext port for IRC is 6667. Allowing plaintext over the&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# public Internet poses serious security and privacy issues. Accordingly,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# we recommend using plaintext only on local (loopback) interfaces:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;127.0.0.1:6667&amp;#34;: &lt;/span&gt;&lt;span style="color:#75715e"&gt;# (loopback ipv4, localhost-only)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;[::1]:6667&amp;#34;: &lt;/span&gt; &lt;span style="color:#75715e"&gt;# (loopback ipv6, localhost-only)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# If you need to serve plaintext on public interfaces, comment out the above&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# two lines and uncomment the line below (which listens on all interfaces):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;:6667&amp;#34;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Alternately, if you have a TLS certificate issued by a recognized CA,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# you can configure port 6667 as an STS-only listener that only serves&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;redirects&amp;#34; to the TLS port, but doesn&amp;#39;t allow chat. See the manual&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# for details.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# The standard SSL/TLS port for IRC is 6697. This will listen on all interfaces:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;:6697&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tls&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cert&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fullchain.pem&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;key&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;privkey.pem&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#39;proxy&amp;#39; should typically be false. It&amp;#39;s only for Kubernetes-style load&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# balancing that does not terminate TLS, but sends an initial PROXY line&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# in plaintext.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;proxy&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Example of a Unix domain socket for proxying:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;/tmp/oragono_sock&amp;#34;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Example of a Tor listener: any connection that comes in on this listener will&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# be considered a Tor connection. It is strongly recommended that this listener&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# *not* be on a public interface --- it should be on 127.0.0.0/8 or unix domain:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;/hidden_service_sockets/oragono_tor_sock&amp;#34;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# tor: true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Example of a WebSocket listener:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;:8097&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;websocket&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tls&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cert&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fullchain.pem&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;key&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;privkey.pem&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ircd operators&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;opers&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# operator named &amp;#39;admin&amp;#39;; log in with /OPER admin [password]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;admin&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# which capabilities this oper has access to&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;class&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;server-admin&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# custom whois line&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;whois-line&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;is a server admin&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# custom hostname&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;vhost&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;staff&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# normally, operator status is visible to unprivileged users in WHO and WHOIS&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# responses. this can be disabled with &amp;#39;hidden&amp;#39;. (&amp;#39;hidden&amp;#39; also causes the&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#39;vhost&amp;#39; line above to be ignored.)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;hidden&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# modes are modes to auto-set upon opering-up. uncomment this to automatically&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# enable snomasks (&amp;#34;server notification masks&amp;#34; that alert you to server events;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# see `/quote help snomasks` while opered-up for more information):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#modes: +is acjknoqtuxv&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# operators can be authenticated either by password (with the /OPER command),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# or by certificate fingerprint, or both. if a password hash is set, then a&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# password is required to oper up (e.g., /OPER dan mypassword). to generate&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# the hash, use `oragono genpasswd`.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;password&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;$2a$04$I2Yhr7UF4p3iyEZcKTPJgukLA9mm00B1wQgicJvGZP/gf0u0tbQQy&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# datastore configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;datastore&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# path to the datastore&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ircd.db&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# if the database schema requires an upgrade, `autoupgrade` will attempt to&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# perform it automatically on startup. the database will be backed&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# up, and if the upgrade fails, the original database will be restored.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;autoupgrade&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# connection information for MySQL (currently only used for persistent history):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;mysql&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;enabled&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;host&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;port&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3306&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# if socket-path is set, it will be used instead of host:port&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#socket-path: &amp;#34;/var/run/mysqld/mysqld.sock&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;user&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;password&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;history-database&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;oragono_history&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;timeout&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;IRC服务端设置好了，使用客户端连上去就可以聊天了。IRC协议类似HTTP协议，服务器地址类似irc://irc.freenode.net，但是也可以使用web来连接，前面配置了监听来自8097端口的websocket请求。这里使用web的IRC客户端&lt;a class="link" href="https://kiwiirc.com/" target="_blank" rel="noopener"&#10; &gt;Kiwi IRC&lt;/a&gt;，这是Vue实现的一个web客户端，各个组件之间通过触发/订阅Vue实例状态/事件变化进行通信，支持自定义组件/中间件，这也是Freenode使用的客户端。Kiwiirc主要聚焦连接和消息的处理，比如websocket连接/发送/监听，消息的格式化/通知/声音/状态。它能够连接websocket的IRC服务器，甚至还提供在线&lt;a class="link" href="https://kiwiirc.com/clientbuilder/#/" target="_blank" rel="noopener"&#10; &gt;生成器&lt;/a&gt;，只需要添加websocket url就好了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;windowTitle&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Kiwi IRC with Oragono Test&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;startupScreen&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;welcome&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;kiwiServer&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;http://oragono.test&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;restricted&amp;#34;&lt;/span&gt;: false,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;theme&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;themes&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/default&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Dark&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/dark&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Coffee&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/coffee&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;GrayFox&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/grayfox&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Nightswatch&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/nightswatch&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Osprey&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/osprey&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Radioactive&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/radioactive&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Sky&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/sky&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Elite&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/elite&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;startupOptions&amp;#34;&lt;/span&gt; : &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;websocket&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;wss://127.0.0.1:8097&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;channel&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;#kiwiirc-default&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;nick&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;kiwi-n?&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;embedly&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;plugins&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;customise&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/plugins/customise.html&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行登录后的效果&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_action.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="310px" data-flex-grow="129" height="232" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_action-300x232.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_auth.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="566px" data-flex-grow="236" height="127" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_auth-300x127.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_auth_no.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="660px" data-flex-grow="275" height="109" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_auth_no-300x109.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_channel.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="960px" data-flex-grow="400" height="75" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_channel-300x75.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_channel_register.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="406px" data-flex-grow="169" height="177" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_channel_register-300x177.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_invite.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="293px" data-flex-grow="122" height="245" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_invite-300x245.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_join_history.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="431px" data-flex-grow="179" height="167" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_join_history-300x167.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_join_self.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="452px" data-flex-grow="188" height="159" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_join_self-300x159.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_login.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="566px" data-flex-grow="236" height="127" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_login-300x127.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_oper.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="231px" data-flex-grow="96" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_oper-289x300.png" width="289"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_preload.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="489px" data-flex-grow="204" height="147" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_preload-300x147.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;其实IRC是基于TCP连接的文本交互的，也可以使用telnet来模拟&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ telnet 127.0.0.1 &lt;span style="color:#ae81ff"&gt;6667&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Trying 127.0.0.1...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connected to localhost.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Escape character is &lt;span style="color:#e6db74"&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CAP LS &lt;span style="color:#ae81ff"&gt;302&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:oragono.test CAP * LS * :account-notify account-tag away-notify batch cap-notify chghost draft/channel-rename draft/chathistory draft/event-playback draft/languages&lt;span style="color:#f92672"&gt;=&lt;/span&gt;16,en,~bs,~de,~el,~en-AU,~es,~fi,~fr-FR,~it,~nl,~no,~pl,~pt-BR,~ro,~tr-TR,~zh-CN draft/multiline&lt;span style="color:#f92672"&gt;=&lt;/span&gt;max-bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;4096,max-lines&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; draft/register&lt;span style="color:#f92672"&gt;=&lt;/span&gt;before-connect draft/relaymsg&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/ draft/resume-0.5 echo-message extended-join invite-notify labeled-response message-tags multi-prefix oragono.io/nope sasl&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PLAIN,EXTERNAL server-time setname&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:oragono.test CAP * LS :userhost-in-names znc.in/playback znc.in/self-message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NICK kiwi-n26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;USER kiwi-n26 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; * https://kiwiirc.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CAP REQ :account-notify account-tag away-notify batch cap-notify draft/chathistory extended-join invite-notify message-tags multi-prefix server-time userhost-in-names znc.in/self-message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:02.201Z :oragono.test CAP * ACK :account-notify account-tag away-notify batch cap-notify draft/chathistory extended-join invite-notify message-tags multi-prefix server-time userhost-in-names znc.in/self-message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CAP END&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;001&lt;/span&gt; kiwi-n26 :Welcome to the Internet Relay Network kiwi-n26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;002&lt;/span&gt; kiwi-n26 :Your host is oragono.test, running version oragono-2.4.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;003&lt;/span&gt; kiwi-n26 :This server was created Fri, &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; Nov &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; 00:35:48 UTC&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;004&lt;/span&gt; kiwi-n26 oragono.test oragono-2.4.0 BERTZios CEIMRUabehiklmnoqstuv Iabehkloqv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;005&lt;/span&gt; kiwi-n26 AWAYLEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;390&lt;/span&gt; BOT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;B CASEMAPPING&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ascii CHANLIMIT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#75715e"&gt;#:100 CHANMODES=Ibe,k,l,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS EXTBAN=,m INVEX KICKLEN=390 MAXLIST=beI:60 :are supported by this server&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;005&lt;/span&gt; kiwi-n26 MAXTARGETS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; MODES MONITOR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; NETWORK&lt;span style="color:#f92672"&gt;=&lt;/span&gt;OragonoTest NICKLEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; PREFIX&lt;span style="color:#f92672"&gt;=(&lt;/span&gt;qaohv&lt;span style="color:#f92672"&gt;)&lt;/span&gt;~&amp;amp;@%+ STATUSMSG&lt;span style="color:#f92672"&gt;=&lt;/span&gt;~&amp;amp;@%+ TARGMAX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;390&lt;/span&gt; UTF8MAPPING&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rfc8265 WHOX draft/CHATHISTORY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; :are supported by this server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;251&lt;/span&gt; kiwi-n26 :There are &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; users and &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; invisible on &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; server&lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;252&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :IRC Operators online&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;253&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :unregistered connections&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;254&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; :channels formed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt; kiwi-n26 :I have &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; clients and &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; servers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;265&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; :Current local users 4, max &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;266&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; :Current global users 4, max &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;375&lt;/span&gt; kiwi-n26 :- oragono.test Message of the day -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▄▄▄ ▄▄▄· ▄▄ • ▐ ▄&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▪ ▀▄ █·▐█ ▀█ ▐█ ▀ ▪▪ •█▌▐█▪&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▄█▀▄ ▐▀▀▄ ▄█▀▀█ ▄█ ▀█▄ ▄█▀▄▪▐█▐▐▌ ▄█▀▄&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▐█▌.▐▌▐█•█▌▐█ ▪▐▌▐█▄▪▐█▐█▌ ▐▌██▐█▌▐█▌.▐▌&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▀█▄▀▪.▀ ▀ ▀ ▀ ·▀▀▀▀ ▀█▄▀ ▀▀ █▪ ▀█▄▀▪&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- This is the default Oragono MOTD.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- If motd-formatting is enabled in the config file, you can use the dollarsign character to&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- create special formatting such as bold, italics and color codes.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- For example, here are a few formatted lines &lt;span style="color:#f92672"&gt;(&lt;/span&gt;enable motd-formatting to see these in action&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is bold text.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is italics text.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is 4red and 2blue text.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is 4,12red text with a light blue background.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is a normal escaped dollarsign: $&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- And now a few fun colour charts!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 1,0 &lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; 0,1 &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; 0,2 &lt;span style="color:#ae81ff"&gt;02&lt;/span&gt; 0,3 &lt;span style="color:#ae81ff"&gt;03&lt;/span&gt; 1,4 &lt;span style="color:#ae81ff"&gt;04&lt;/span&gt; 0,5 &lt;span style="color:#ae81ff"&gt;05&lt;/span&gt; 0,6 &lt;span style="color:#ae81ff"&gt;06&lt;/span&gt; 1,7 &lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 1,8 &lt;span style="color:#ae81ff"&gt;08&lt;/span&gt; 1,9 &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt; 0,10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; 1,11 &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; 0,12 &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; 1,13 &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; 1,14 &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; 1,15 &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,16 &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; 0,17 &lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; 0,18 &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt; 0,19 &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0,20 &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; 0,21 &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt; 0,22 &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; 0,23 &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; 0,24 &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; 0,25 &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt; 0,26 &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; 0,27 &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,28 &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; 0,29 &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 0,30 &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; 0,31 &lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; 0,32 &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; 0,33 &lt;span style="color:#ae81ff"&gt;33&lt;/span&gt; 0,34 &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; 0,35 &lt;span style="color:#ae81ff"&gt;35&lt;/span&gt; 0,36 &lt;span style="color:#ae81ff"&gt;36&lt;/span&gt; 0,37 &lt;span style="color:#ae81ff"&gt;37&lt;/span&gt; 0,38 &lt;span style="color:#ae81ff"&gt;38&lt;/span&gt; 0,39 &lt;span style="color:#ae81ff"&gt;39&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,40 &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt; 0,41 &lt;span style="color:#ae81ff"&gt;41&lt;/span&gt; 0,42 &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt; 0,43 &lt;span style="color:#ae81ff"&gt;43&lt;/span&gt; 0,44 &lt;span style="color:#ae81ff"&gt;44&lt;/span&gt; 0,45 &lt;span style="color:#ae81ff"&gt;45&lt;/span&gt; 0,46 &lt;span style="color:#ae81ff"&gt;46&lt;/span&gt; 0,47 &lt;span style="color:#ae81ff"&gt;47&lt;/span&gt; 0,48 &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt; 0,49 &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; 0,50 &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; 0,51 &lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,52 &lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; 0,53 &lt;span style="color:#ae81ff"&gt;53&lt;/span&gt; 1,54 &lt;span style="color:#ae81ff"&gt;54&lt;/span&gt; 1,55 &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; 1,56 &lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; 1,57 &lt;span style="color:#ae81ff"&gt;57&lt;/span&gt; 1,58 &lt;span style="color:#ae81ff"&gt;58&lt;/span&gt; 0,59 &lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; 0,60 &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; 0,61 &lt;span style="color:#ae81ff"&gt;61&lt;/span&gt; 0,62 &lt;span style="color:#ae81ff"&gt;62&lt;/span&gt; 0,63 &lt;span style="color:#ae81ff"&gt;63&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,64 &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt; 1,65 &lt;span style="color:#ae81ff"&gt;65&lt;/span&gt; 1,66 &lt;span style="color:#ae81ff"&gt;66&lt;/span&gt; 1,67 &lt;span style="color:#ae81ff"&gt;67&lt;/span&gt; 1,68 &lt;span style="color:#ae81ff"&gt;68&lt;/span&gt; 1,69 &lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; 1,70 &lt;span style="color:#ae81ff"&gt;70&lt;/span&gt; 1,71 &lt;span style="color:#ae81ff"&gt;71&lt;/span&gt; 0,72 &lt;span style="color:#ae81ff"&gt;72&lt;/span&gt; 0,73 &lt;span style="color:#ae81ff"&gt;73&lt;/span&gt; 0,74 &lt;span style="color:#ae81ff"&gt;74&lt;/span&gt; 0,75 &lt;span style="color:#ae81ff"&gt;75&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 1,76 &lt;span style="color:#ae81ff"&gt;76&lt;/span&gt; 1,77 &lt;span style="color:#ae81ff"&gt;77&lt;/span&gt; 1,78 &lt;span style="color:#ae81ff"&gt;78&lt;/span&gt; 1,79 &lt;span style="color:#ae81ff"&gt;79&lt;/span&gt; 1,80 &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt; 1,81 &lt;span style="color:#ae81ff"&gt;81&lt;/span&gt; 1,82 &lt;span style="color:#ae81ff"&gt;82&lt;/span&gt; 1,83 &lt;span style="color:#ae81ff"&gt;83&lt;/span&gt; 1,84 &lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; 1,85 &lt;span style="color:#ae81ff"&gt;85&lt;/span&gt; 1,86 &lt;span style="color:#ae81ff"&gt;86&lt;/span&gt; 1,87 &lt;span style="color:#ae81ff"&gt;87&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,88 &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; 0,89 &lt;span style="color:#ae81ff"&gt;89&lt;/span&gt; 0,90 &lt;span style="color:#ae81ff"&gt;90&lt;/span&gt; 0,91 &lt;span style="color:#ae81ff"&gt;91&lt;/span&gt; 0,92 &lt;span style="color:#ae81ff"&gt;92&lt;/span&gt; 0,93 &lt;span style="color:#ae81ff"&gt;93&lt;/span&gt; 0,94 &lt;span style="color:#ae81ff"&gt;94&lt;/span&gt; 0,95 &lt;span style="color:#ae81ff"&gt;95&lt;/span&gt; 1,96 &lt;span style="color:#ae81ff"&gt;96&lt;/span&gt; 1,97 &lt;span style="color:#ae81ff"&gt;97&lt;/span&gt; 1,98 &lt;span style="color:#ae81ff"&gt;98&lt;/span&gt; 99,99 &lt;span style="color:#ae81ff"&gt;99&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- For more information on using these, see MOTDFORMATTING.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;376&lt;/span&gt; kiwi-n26 :End of MOTD command&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.715Z :oragono.test &lt;span style="color:#ae81ff"&gt;221&lt;/span&gt; kiwi-n26 +Zi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WHO kiwi-n26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:15.649Z :oragono.test &lt;span style="color:#ae81ff"&gt;352&lt;/span&gt; kiwi-n26 * ~u gcjc79gmtbe42.irc oragono.test kiwi-n26 H :0 https://kiwiirc.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:15.649Z :oragono.test &lt;span style="color:#ae81ff"&gt;315&lt;/span&gt; kiwi-n26 kiwi-n26!*@* :End of WHO list&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;JOIN &lt;span style="color:#75715e"&gt;#kiwiirc-default&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@msgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;bidkvpja5njjtgchub8u65pxgn;time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:26.706Z :kiwi-n26!~u@gcjc79gmtbe42.irc JOIN &lt;span style="color:#75715e"&gt;#kiwiirc-default * https://kiwiirc.com/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:26.706Z :oragono.test &lt;span style="color:#ae81ff"&gt;353&lt;/span&gt; kiwi-n26 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#75715e"&gt;#kiwiirc-default :@kiwi-n28!~u@5g96q93tqw3vn.irc kiwi-n30!~u@5g96q93tqw3vn.irc kiwi-n29!~u@5g96q93tqw3vn.irc kiwi-n26!~u@gcjc79gmtbe42.irc&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:26.706Z :oragono.test &lt;span style="color:#ae81ff"&gt;366&lt;/span&gt; kiwi-n26 &lt;span style="color:#75715e"&gt;#kiwiirc-default :End of NAMES list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;JOIN &lt;span style="color:#75715e"&gt;#ops&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@msgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;hftqmpu4ieyjybx9bbgf4vpbia;time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:32.145Z :kiwi-n26!~u@gcjc79gmtbe42.irc JOIN &lt;span style="color:#75715e"&gt;#ops * https://kiwiirc.com/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:32.145Z :oragono.test &lt;span style="color:#ae81ff"&gt;353&lt;/span&gt; kiwi-n26 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#75715e"&gt;#ops :@kiwi-n28!~u@5g96q93tqw3vn.irc kiwi-n30!~u@5g96q93tqw3vn.irc kiwi-n29!~u@5g96q93tqw3vn.irc kiwi-n26!~u@gcjc79gmtbe42.irc&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:32.145Z :oragono.test &lt;span style="color:#ae81ff"&gt;366&lt;/span&gt; kiwi-n26 &lt;span style="color:#75715e"&gt;#ops :End of NAMES list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PRIVMSG &lt;span style="color:#75715e"&gt;#ops hello&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PRIVMSG &lt;span style="color:#75715e"&gt;#ops :kiwi-n28 good morning&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PRIVMSG kiwi-n28 &lt;span style="color:#f92672"&gt;=&lt;/span&gt;D&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PING kiwitime-1605232555315&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:57:14.150Z :oragono.test PONG oragono.test kiwitime-1605232555315&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHATHISTORY BEFORE kiwi-n28 * &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:57:38.462Z :oragono.test BATCH +1 chathistory kiwi-n28&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@msgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rqdbvmytzppssc5ymp7ffhmkga;time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:56:05.705Z;batch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; :kiwi-n26!~u@gcjc79gmtbe42.irc PRIVMSG kiwi-n28 :&lt;span style="color:#f92672"&gt;=&lt;/span&gt;D&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:57:38.462Z :oragono.test BATCH -1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:59:08.466Z PING kiwi-n26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:kiwi-n26!~u@gcjc79gmtbe42.irc QUIT :Ping timeout: 2m30s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR :Ping timeout: 2m30s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connection closed by foreign host.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到这些消息都带有一定的格式，客户端根据特地的格式解析就可以个性化显示来。带有符号@/：前缀的消息都是服务器推送下来的消息，反之都是客户端请求的消息。“CAP LS 302”即协商会话协议版本，随即用命令“NICK ”设置昵称（登录名），和“USER 0 * ”设置该昵称显示的用户名，最后以“CAP END”结束协商，开始会话。服务端推送过来的消息格式为时间戳+服务器+响应码+接受者昵称+消息内容，即“@time=2020-11-13T01:55:07.714Z :oragono.test 001 :Welcome to the Internet Relay Network ”，001代表欢迎信息，具体响应码可以参考&lt;a class="link" href="https://tools.ietf.org/html/rfc2812#section-5.2" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。客户端发送消息则直接发送，比如使用“JOIN #channel”加入某个频道，服务器会向该频道里的每个人广播对JOIN应的消息“@msgid=hftqmpu4ieyjybx9bbgf4vpbia;time=2020-11-13T01:55:32.145Z :@gcjc79gmtbe42.irc JOIN #channel * ”并向操作者推送频道用户列表“@time=2020-11-13T01:55:32.145Z :oragono.test 353 = #channel :@!~&lt;a class="link" href="mailto:u@5g96q93tqw3vn.irc" &gt;u@5g96q93tqw3vn.irc&lt;/a&gt; !~&lt;a class="link" href="mailto:u@5g96q93tqw3vn.irc" &gt;u@5g96q93tqw3vn.irc&lt;/a&gt; !~&lt;a class="link" href="mailto:u@5g96q93tqw3vn.irc" &gt;u@5g96q93tqw3vn.irc&lt;/a&gt;&lt;br&gt;&#10;”。Twitch则在消息的基础上加入了其他格式化控制，比如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@badge-info&lt;span style="color:#f92672"&gt;=&lt;/span&gt;;badges&lt;span style="color:#f92672"&gt;=&lt;/span&gt;premium/1;client-nonce&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2f70a1efd6f84523d0f180cc44f76c61;color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#75715e"&gt;#B22222;display-name=Khodeine;emotes=58765:9-19;flags=;id=50d8790f-c474-42a8-b873-2d5e8008bd52;mod=0;room-id=30220059;subscriber=0;tmi-sent-ts=1605279854692;turbo=0;user-id=49980352;user-type= :khodeine!khodeine@khodeine.tmi.twitch.tv PRIVMSG #esl_sc2 :the scvs NotLikeThis&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;会显示以一定的颜色/图标显示用户名/消息。空闲状态下IRC服务端与客户端需要维持心跳信息，比如“PING kiwitime-1605232555315”和“time=2020-11-13T01:57:14.150Z :oragono.test PONG oragono.test kiwitime-1605232555315”，否则连接会被关闭。一些常用的命令，可以看出IRC交互非常简单，&lt;a class="link" href="https://en.wikipedia.org/wiki/IRC_services" target="_blank" rel="noopener"&#10; &gt;IRC核心组件&lt;/a&gt;也不多。使用“@+dratf/typing=active TAGMSG ”显示输入状态，借助&lt;a class="link" href="https://tools.ietf.org/id/draft-oakley-irc-ctcp-01.html" target="_blank" rel="noopener"&#10; &gt;CTCP&lt;/a&gt;协议甚至可以点对点发送文件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#使用password注册当前nickname&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/NS REGISTER &amp;lt;your password&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#注册一个频道&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/CS REGISTER &lt;span style="color:#75715e"&gt;#channelname&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/CS REGISTER &lt;span style="color:#75715e"&gt;#channe&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#要去某人加入频道&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/INVITE nickname &lt;span style="color:#75715e"&gt;#channel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#给予某个用户频道管理权限&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/mode +o nickname&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#认证成为管理员&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/OPER admin &amp;lt;admin passowrd&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#在频道发送消息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/PRIVMSG &lt;span style="color:#75715e"&gt;#channe hello&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#给频道某人发送消息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/PRIVMSG &lt;span style="color:#75715e"&gt;#channe :&amp;lt;nick&amp;gt; good morning&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#给频道某人发送消息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/INVITE &amp;lt;nick&amp;gt; &lt;span style="color:#75715e"&gt;#channe&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#使用密码登录&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AUTHENTICATE PLAIN&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AUTHENTICATE +&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AUTHENTICATE a2l3aS1uMzAAa2l3aS1uMzAAMTAyMDMwNDA&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="link" href="https://thelounge.chat/" target="_blank" rel="noopener"&#10; &gt;Thelounge&lt;/a&gt;是另外一个Vue实现的web的IRC客户端，同样支持websocket。它还用express实现了服务端，支持额外的密码/LDAP登录，即先认证通过才能连接IRC服务器，它本身也可以作为一个服务代理网关，为用户提供永远在线服务/消息存储-如果一个IRC用户不在线是不能够给它发送消息的，这一点也跟XMPP不一样。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/lounge_join.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="480px" data-flex-grow="200" height="150" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/lounge_join-300x150.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/lounge_send.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="431px" data-flex-grow="179" height="167" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/lounge_send-300x167.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;Kiwiirc和Thelounge的设计实现良好，可以作为web chat实现的参考，比如在线客服/销售。比较两个web的IRC客户端发现，他们使用的websocket库并不一样。Kiwiirc使用的是&lt;a class="link" href="https://github.com/sockjs/sockjs-client" target="_blank" rel="noopener"&#10; &gt;sockjs-client&lt;/a&gt;，一个类似websocket的JavaScript网络连接库，支持不同浏览器，能够跨域名通信，在浏览器不支持websocket的情况下退化为&lt;a class="link" href="https://www.pubnub.com/blog/http-long-polling/" target="_blank" rel="noopener"&#10; &gt;polling&lt;/a&gt;（需要&lt;a class="link" href="https://github.com/sockjs/sockjs-node" target="_blank" rel="noopener"&#10; &gt;服务端&lt;/a&gt;配合）。而Thelounge使用的是&lt;a class="link" href="https://github.com/socketio/socket.io" target="_blank" rel="noopener"&#10; &gt;socket.io&lt;/a&gt;。Socket.IO由Engine.IO发展而来，致力于为web提供实时通信能力。Socket.IO并不是WebSocket的一个实现，只是提供了类似的连接能力，需要服务端配合。两个连接库在浏览器支持websocket的情况下都可以直接与websocket服务端通信（不需要对应的库）。Kiwiirc还提供了irc-framework开发库，可以快速搭建一个IRC客户端，比如IRC Bot。至今仍然存在着许多&lt;a class="link" href="https://en.wikipedia.org/wiki/IRC_bot" target="_blank" rel="noopener"&#10; &gt;IRC聊天机器人&lt;/a&gt;，为用户提供方便/服务器报警。Twitch一个用户加入频道时甚至能收到广告！&lt;/p&gt;&#10;&lt;p&gt;Websocket提供了与其他socket一样的能力，能够持续连接和双向通讯，甚至可以服用80/443端口（nginx支持101协议升级）。它不止可以使用在web上，也可以使用在非web上面，因为能够穿透防火墙，对树莓派的远程链接支持。传统的web应用都是一应一答，这节省的服务器/客户端的资源能够不需要持续请求的话。而对于有些应用而言，比如消息通知，希望是能够持续从服务器推送的，websocket增强了它的能力，在这之前都是long polling（所以才有那些包装库）。&lt;br&gt;&#10;Http协议在tcp基础上实现，请求头里面带有host、cookie，url里面带有路径等，这样后端能够识别、路由、分发请求。而tcp并没有这些，websocket必须自己实现类似的路由分发/调用，可以在连接建立初期，鉴别授权（可以在url上面带参数token/jwt/security key），对于后续消息的应答可以在url上面指定，也可以在事件上面指定。这样实现出来似乎与http差不多，仍然有event对应route，但却可以持续交互。&lt;br&gt;&#10;再观察IRC协议也不过是对各个命令的应答，其实也跟经典web MVC差不多-使用URL映射对应的controller/action。IRC每个会话都是一个队列，join #channel命令即订阅消息，part #channel命令则是取消订阅。再看Rabbitmq消息队列，实现了exchange，route，queue，channel，topic等，然后是持续的消费/推送，与前面所诉差不多，这样子看IRC也是个消息服务器。IRC实现简单，通过扩展支持的命令，也能够与内部/外部系统结合，快速搭建一个即时消息平台。&lt;br&gt;&#10;再看邮件服务，其实也是消息服务，也有一对一/群发消息/历史消息，甚至能够给不认识（不在线）的人发送邮件！而邮件服务至今流行，在许多平台，不论服务器还是手机都自带，不需要额外安装软件。&lt;a class="link" href="https://slack.com/intl/en-cn/features" target="_blank" rel="noopener"&#10; &gt;Slack&lt;/a&gt;的产品宣传即对比了自己相对邮件服务的优势。其实手机默认带的电话和短信功能是基于硬件模块的在线功能。&lt;br&gt;&#10;相比Ejabberd/Openfire，IRC服务器的部署简单许多，甚至可以部署在树莓派上！&lt;/p&gt;&#10;&lt;p&gt;参考连接：&lt;br&gt;&#10;&lt;a class="link" href="http://IRC%20bot" target="_blank" rel="noopener"&#10; &gt;IRC Bot&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://developer.ibm.com/zh/technologies/messaging/articles/os-cn-rabbit-mq/" target="_blank" rel="noopener"&#10; &gt;基于 RabbitMQ 的实时消息推送&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>即时通信XMPP服务器ejabberd/Openfire</title><link>https://courages.us/%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1xmpp%E6%9C%8D%E5%8A%A1%E5%99%A8ejabberd-openfire/</link><pubDate>Thu, 05 Nov 2020 17:14:06 +0800</pubDate><guid>https://courages.us/%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1xmpp%E6%9C%8D%E5%8A%A1%E5%99%A8ejabberd-openfire/</guid><description>&lt;p&gt;即时通信的需求，不仅在公共互联网上，比如微信、QQ，也在企业的内部网络，特别是与内部系统的整合，比如OA、客服系统。&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E5%8F%AF%E6%89%A9%E5%B1%95%E6%B6%88%E6%81%AF%E4%B8%8E%E5%AD%98%E5%9C%A8%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;XMPP&lt;/a&gt;，也叫扩展消息与存在协议，是一种以XML为基础的开放式即时通信协议。&lt;a class="link" href="https://xmpp.org/" target="_blank" rel="noopener"&#10; &gt;XMPP&lt;/a&gt;不但能够用来做消息通信（单聊/群聊/订阅），也可以做语音通信。XMPP甚至支持多个服务器之间互相连接，互相通信，早期Gtalk就能够与其他XMPP服务器通信。采用XMPP来开发的好处是，已经有大量的开源服务器（ejabberd、Openfire）和客户端（Spark/Smack/converse.js/XMPPFramework）实现，能够快速搭建。&lt;br&gt;&#10;&lt;a class="link" href="https://www.ejabberd.im/" target="_blank" rel="noopener"&#10; &gt;Ejabberd&lt;/a&gt;则是ProcessOne出品的，基于Erlang开发的XMPP/MQTT/SIP服务器，内置了WebSocket/文件上传支持，提供更加丰富的&lt;a class="link" href="https://docs.ejabberd.im/developer/ejabberd-api/" target="_blank" rel="noopener"&#10; &gt;REST API&lt;/a&gt;。在CentOS64下面安装Ejabberd，会安装到/etc/init.d/ejabberd，直接service start ejabberd就好了，可以使用&lt;a class="link" href="https://github.com/processone/docker-ejabberd" target="_blank" rel="noopener"&#10; &gt;docker&lt;/a&gt;快速启用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# wget https://static.process-one.net/ejabberd/downloads/20.04/ejabberd-20.04-0.x86_64.rpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--2020-10-29 08:26:16--  https://static.process-one.net/ejabberd/downloads/20.04/ejabberd-20.04-0.x86_64.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Resolving static.process-one.net... 13.226.36.69, 13.226.36.105, 13.226.36.34, ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connecting to static.process-one.net|13.226.36.69|:443... connected.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTP request sent, awaiting response... &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; OK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Length: &lt;span style="color:#ae81ff"&gt;18713774&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;18M&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;application/x-rpm&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Saving to: “ejabberd-20.04-0.x86_64.rpm”&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;100%&lt;span style="color:#f92672"&gt;[====================================================================================================================================================================================================================================&lt;/span&gt;&amp;gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; 18,713,774  2.84M/s   in 9.1s    &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-10-29 08:26:27 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.96 MB/s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; - “ejabberd-20.04-0.x86_64.rpm” saved &lt;span style="color:#f92672"&gt;[&lt;/span&gt;18713774/18713774&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# yum localinstall ejabberd-20.04-0.x86_64.rpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loaded plugins: fastestmirror&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Setting up Local Package Process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Examining ejabberd-20.04-0.x86_64.rpm: ejabberd-20.04-0.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Marking ejabberd-20.04-0.x86_64.rpm to be installed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loading mirror speeds from cached hostfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * base: mirrors.163.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * epel: mirror.math.princeton.edu&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * extras: mirrors.cn99.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * updates: mirrors.cn99.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * webtatic: uk.repo.webtatic.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon_stable/signature                                                                                                                                                                                                                               |  &lt;span style="color:#ae81ff"&gt;819&lt;/span&gt; B     00:00     &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon_stable/signature                                                                                                                                                                                                                               |  &lt;span style="color:#ae81ff"&gt;951&lt;/span&gt; B     00:00 ... &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon_stable-source/signature                                                                                                                                                                                                                        |  &lt;span style="color:#ae81ff"&gt;819&lt;/span&gt; B     00:00     &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon_stable-source/signature                                                                                                                                                                                                                        |  &lt;span style="color:#ae81ff"&gt;951&lt;/span&gt; B     00:00 ... &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Resolving Dependencies&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--&amp;gt; Running transaction check&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---&amp;gt; Package ejabberd.x86_64 0:20.04-0 will be installed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--&amp;gt; Finished Dependency Resolution&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Dependencies Resolved&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==============================================================================================================================================================================================================================================================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Package                                                       Arch                                                        Version                                                        Repository                                                                     Size&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==============================================================================================================================================================================================================================================================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installing:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ejabberd                                                      x86_64                                                      20.04-0                                                        /ejabberd-20.04-0.x86_64                                                       &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; M&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Transaction Summary&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==============================================================================================================================================================================================================================================================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Install       &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; Package&lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Total size: &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; M&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installed size: &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; M&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Is this ok &lt;span style="color:#f92672"&gt;[&lt;/span&gt;y/N&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Downloading Packages:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Running rpm_check_debug&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Running Transaction Test&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Transaction Test Succeeded&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Running Transaction&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  Installing : ejabberd-20.04-0.x86_64                                                                                                                                                                                                                                    1/1 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  Verifying  : ejabberd-20.04-0.x86_64                                                                                                                                                                                                                                    1/1 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installed:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  ejabberd.x86_64 0:20.04-0                                                                                                                                                                                                                                                   &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Complete!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ls  /etc/init.d/ejabberd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/etc/init.d/ejabberd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ls -la /opt/ejabberd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x  &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; ejabberd ejabberd &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x. &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; root     root     &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x  &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; ejabberd ejabberd &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x  &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; ejabberd ejabberd &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 database&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-r--------  &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ejabberd ejabberd   &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 00:00 .erlang.cookie&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x  &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; ejabberd ejabberd &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 logs&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# service ejabberd start&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting ejabberd...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 sql&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ps aux | grep ejabberd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ejabberd 10097  0.2  7.9 &lt;span style="color:#ae81ff"&gt;1817344&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;48144&lt;/span&gt; ?       Sl   08:51   0:04 /opt/ejabberd-20.04/bin/beam.smp -K true -P &lt;span style="color:#ae81ff"&gt;250000&lt;/span&gt; -- -root /opt/ejabberd-20.04 -progname /opt/ejabberd-20.04/bin/erl -- -home /opt/ejabberd -- -sname ejabberd@localhost -smp enable -mnesia dir &lt;span style="color:#e6db74"&gt;&amp;#34;/opt/ejabberd/database/ejabberd@localhost&amp;#34;&lt;/span&gt; -ejabberd log_rate_limit &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; log_rotate_size &lt;span style="color:#ae81ff"&gt;10485760&lt;/span&gt; log_rotate_count &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; log_rotate_date &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt; -s ejabberd -noshell -noinput&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ejabberd 10105  0.0  0.0   &lt;span style="color:#ae81ff"&gt;4060&lt;/span&gt;   &lt;span style="color:#ae81ff"&gt;496&lt;/span&gt; ?        Ss   08:51   0:00 erl_child_setup &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ejabberd 10186  0.0  0.0   &lt;span style="color:#ae81ff"&gt;4052&lt;/span&gt;   &lt;span style="color:#ae81ff"&gt;572&lt;/span&gt; ?        Ss   08:51   0:00 /opt/ejabberd-20.04/lib/os_mon-2.4.7/priv/bin/memsup&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root     11215  0.0  0.1 &lt;span style="color:#ae81ff"&gt;103324&lt;/span&gt;   &lt;span style="color:#ae81ff"&gt;892&lt;/span&gt; pts/4    S+   09:16   0:00 grep ejabberd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# netstat -apn | grep beam&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:7777              0.0.0.0:*                   LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0.0.0.0:37617               0.0.0.0:*                   LISTEN      1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0.0.0.0:15672               0.0.0.0:*                   LISTEN      1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0.0.0.0:55672               0.0.0.0:*                   LISTEN      1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0.0.0.0:43674               0.0.0.0:*                   LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:44055             127.0.0.1:4369              ESTABLISHED 1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:35415             127.0.0.1:4369              ESTABLISHED 10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5280                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5443                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5222                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5672                     :::*                        LISTEN      1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5269                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::1883                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;unix  3      &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;         STREAM     CONNECTED     &lt;span style="color:#ae81ff"&gt;1637533&lt;/span&gt; 10097/beam.smp   &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ejabberd自带Erlang的数据库服务Mnesia，但有一些限制建议使用第三方的比如MySQL，这样也方便第三方交互（比如认证Token）。初始化的SQL脚本在/opt/ejabberd-20.04/lib/ejabberd-20.04/priv/sql，如果只是支持单个domain的话使用mysql.sql就可以了，多domain支持使用mysql.new.sql&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 sql&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lite.new.sql  lite.sql  mssql.sql  mysql.new.sql  mysql.sql  pg.new.sql  pg.sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 sql&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# pwd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/opt/ejabberd-20.04/lib/ejabberd-20.04/priv/sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改为使用&lt;a class="link" href="https://docs.ejabberd.im/tutorials/mysql/" target="_blank" rel="noopener"&#10; &gt;MySQL&lt;/a&gt;存储和认证&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# cat /opt/ejabberd/conf/ejabberd.yml&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&amp;#39; ejabberd configuration file&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### The parameters used in this configuration file are explained at&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### https://docs.ejabberd.im/admin/configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### The configuration file is written in YAML.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### *******************************************************&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### ******* !!! WARNING !!! *******&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### ******* YAML IS INDENTATION SENSITIVE *******&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### ******* MAKE SURE YOU INDENT SECTIONS CORRECTLY *******&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### *******************************************************&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;vagrant-centos64&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loglevel: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_rotate_size: &lt;span style="color:#ae81ff"&gt;10485760&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_rotate_date: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_rotate_count: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_rate_limit: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certfiles:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;/opt/ejabberd/conf/server.pem&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## - &amp;#34;/etc/letsencrypt/live/localhost/fullchain.pem&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## - &amp;#34;/etc/letsencrypt/live/localhost/privkey.pem&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ca_file: &lt;span style="color:#e6db74"&gt;&amp;#34;/opt/ejabberd/conf/cacert.pem&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;5222&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: ejabberd_c2s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_stanza_size: &lt;span style="color:#ae81ff"&gt;262144&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shaper: c2s_shaper&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access: c2s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; starttls_required: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;5269&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: ejabberd_s2s_in&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_stanza_size: &lt;span style="color:#ae81ff"&gt;524288&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;5443&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: ejabberd_http&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tls: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request_handlers:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/admin&amp;#34;&lt;/span&gt;: ejabberd_web_admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/api&amp;#34;&lt;/span&gt;: mod_http_api&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/bosh&amp;#34;&lt;/span&gt;: mod_bosh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/captcha&amp;#34;&lt;/span&gt;: ejabberd_captcha&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/upload&amp;#34;&lt;/span&gt;: mod_http_upload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/ws&amp;#34;&lt;/span&gt;: ejabberd_http_ws&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/oauth&amp;#34;&lt;/span&gt;: ejabberd_oauth&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;5280&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: ejabberd_http&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request_handlers:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/admin&amp;#34;&lt;/span&gt;: ejabberd_web_admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;1883&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: mod_mqtt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; backlog: &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s2s_use_starttls: optional&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acl:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; local:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_regexp: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; loopback:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 127.0.0.0/8&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ::1/128&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ::FFFF:127.0.0.1/128&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; admin:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;admin@vagrant-centos64&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;access_rules:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; local:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c2s:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deny: blocked&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; announce:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; configure:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; muc_create:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pubsub_createnode:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; trusted_network:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: loopback&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;api_permissions:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;console commands&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; from:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ejabberd_ctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - mod_http_api&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; who: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; what: &lt;span style="color:#e6db74"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;admin access&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; who:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; acl: loopback&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; acl: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; oauth:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; scope: &lt;span style="color:#e6db74"&gt;&amp;#34;ejabberd:admin&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; acl: loopback&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; acl: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; what:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;!stop&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;!start&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public commands&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; who:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: 127.0.0.1/8&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; what:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - connected_users_number&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shaper:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; normal: &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fast: &lt;span style="color:#ae81ff"&gt;50000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shaper_rules:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_user_sessions: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_user_offline_messages:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 5000: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 100: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c2s_shaper:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; none: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; normal: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; s2s_shaper: fast&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_fsm_queue: &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acme:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; contact: &lt;span style="color:#e6db74"&gt;&amp;#34;mailto:admin@vagrant-centos64&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ca_url: &lt;span style="color:#e6db74"&gt;&amp;#34;https://acme-v01.api.letsencrypt.org&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;modules:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_adhoc: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_admin_extra: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_announce:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access: announce&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_avatar: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_blocking: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_bosh: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_caps: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_carboncopy: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_client_state: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_configure: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_disco: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_fail2ban: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_http_api: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_http_upload:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; put_url: https://@HOST@:5443/upload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_last: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_mam:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## Mnesia is limited to 2GB, better to use an SQL backend&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## For small servers SQLite is a good fit and is very easy&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## to configure. Uncomment this when you have SQL configured:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## db_type: sql&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; assume_mam_usage: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: never&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_mqtt: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_muc:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_admin:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - allow: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_create: muc_create&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_persistent: muc_create&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_mam:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default_room_options:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow_subscription: true &lt;span style="color:#75715e"&gt;# enable MucSub&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mam: false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_muc_admin: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_offline:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_max_user_messages: max_user_offline_messages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_ping: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_privacy: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_private: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_proxy65:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access: local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_connections: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_pubsub:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_createnode: pubsub_createnode&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plugins:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - flat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - pep&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; force_node_config:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## Avoid buggy clients to make their bookmarks public&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; storage:bookmarks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_model: whitelist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_push: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_push_keepalive: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_register:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## Only accept registration requests from the &amp;#34;trusted&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## network (see access_rules section above).&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## Think twice before enabling registration from any&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## address. See the Jabber SPAM Manifesto for details:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## https://github.com/ge0rg/jabber-spam-fighting-manifesto&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip_access: trusted_network&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_roster:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; versioning: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_s2s_dialback: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_shared_roster: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_stream_mgmt:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resend_on_timeout: if_offline&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_vcard: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_vcard_xupdate: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_version:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; show_os: false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth_method: sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_type: mysql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_server: &lt;span style="color:#e6db74"&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_database: &lt;span style="color:#e6db74"&gt;&amp;#34;ejabberd&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_username: &lt;span style="color:#e6db74"&gt;&amp;#34;ejabberd&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_password: &lt;span style="color:#e6db74"&gt;&amp;#34;ejabberd&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_db: sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## If you want to specify the port:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#sql_port: 3306&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### Local Variables:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### mode: yaml&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### End:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### vim: set filetype=yaml tabstop=8&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;试着注册一下管理员&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./ejabberdctl register admin1 localhost admin&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Error: cannot_register&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;失败了，这是因为hostname的关系，在ejabberd.yml配置的host并不是localhost，改一下注册的domain就好了，具体可以参考&lt;a class="link" href="https://www.ejabberd.im/node/14744/index.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;和&lt;a class="link" href="https://github.com/processone/ejabberd/issues/2837" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./ejabberdctl status&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The node ejabberd@localhost is started with status: started&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 logs&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# hostname -s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant-centos64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./ejabberdctl register admin vagrant-centos64 admin&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User admin@vagrant-centos64 successfully registered&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问http://127.0.0.1:5280/admin就可以进入到管理界面了。管理界面比较简单，只能管理用户/消息/聊天室，完整的xmpp协议服务器是支持的，客户端对应实现就好了。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/ejabberd_user.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="486px" data-flex-grow="202" height="148" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/ejabberd_user-300x148.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/ejabberd_message.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="679px" data-flex-grow="283" height="106" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/ejabberd_message-300x106.png" width="300"&gt;&lt;/a&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/ejabberd_muc.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="923px" data-flex-grow="384" height="78" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/ejabberd_muc-300x78.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;使用&lt;a class="link" href="https://conversejs.org/" target="_blank" rel="noopener"&#10; &gt;conversejs&lt;/a&gt;快速搭建一个web客户端来验证一下，创建chat.html&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;chat&lt;span style="color:#f92672"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;media=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;screen&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://cdn.conversejs.org/dist/converse.min.css&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://cdn.conversejs.org/dist/converse.min.js&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charset=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; converse.initialize({&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //bosh_service_url: &amp;#39;http://chat.vagrant-centos64.com/bosh&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; websocket_url: &amp;#39;wss:chat.vagrant-centos64.com/ws&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //show_controlbox_by_default: true,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; view_mode: &amp;#39;fullscreen&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;打开浏览器，访问对应的url登录就可以看到了聊天界面了。这里使用的域名是经过nginx代理转发过的了，配置可以参考&lt;a class="link" href="https://courages.us/api-%e7%bd%91%e5%85%b3-kong/" target="_blank" rel="noopener"&#10; &gt;API 网关 Kong&lt;/a&gt;，如果使用nginx-proxy-servier需要打开Websockets Support，以便进行协议升级101 Switching Protocols。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/convesejs_login.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="365px" data-flex-grow="152" height="197" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/convesejs_login-300x197.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/conversejs_one.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="791px" data-flex-grow="329" height="91" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/conversejs_one-300x91.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/conversejs_chatroom.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="800px" data-flex-grow="333" height="90" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/conversejs_chatroom-300x90.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;conversejs配置里面有两个url，一个是&lt;a class="link" href="https://conversejs.org/docs/html/setup.html#bosh-xmpp-over-http" target="_blank" rel="noopener"&#10; &gt;BOSH&lt;/a&gt;（Bidirectional-streams Over Synchronous HTTP）的，即HTTP长连接，以便通服务器即时交互，获取消息；另一个是WebSocket，基于TCP的，客户端/服务器双向通信。BOHS需要浏览器定时发起一个请求直致服务器返回消息，而WebSocket可以像其他TCP那样双向通信，灵活的多。如果服务端不支持Websocket协议升级或者连接失败conversejs会自动切换使用BOSH通信。如果使用https://www.websocket.org/echo.html来测试连接，需要遵循XMPP协议要求，先认证，否则连接会被关闭。conversejs的认证是在Websocket里面的做的，并不基于cookie之类的，所以一个浏览器打开多个聊天窗口登录不同的账户也是可以的&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/conversejs_con_fail.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="346px" data-flex-grow="144" height="208" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/conversejs_con_fail-300x208.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/conversejs_con_success.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="642px" data-flex-grow="267" height="112" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/conversejs_con_success-300x112.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/converjs_websocket.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="923px" data-flex-grow="384" height="78" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/converjs_websocket-300x78.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;Ejabberd支持&lt;a class="link" href="https://docs.ejabberd.im/developer/ejabberd-api/admin-api/" target="_blank" rel="noopener"&#10; &gt;REST API&lt;/a&gt;来做交互比如查看在线用户、发送消息&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ chat-example git:&lt;span style="color:#f92672"&gt;(&lt;/span&gt;master&lt;span style="color:#f92672"&gt;)&lt;/span&gt; ✗ curl -k https://192.168.33.14:5443/api/connected_users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;admin@vagrant-centos64/converse.js-16142875&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; ➜ chat-example git:&lt;span style="color:#f92672"&gt;(&lt;/span&gt;master&lt;span style="color:#f92672"&gt;)&lt;/span&gt; ✗ curl -k https://192.168.33.14:5443/api/send_message -X POST -d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;type&amp;#34;:&amp;#34;headline&amp;#34;,&amp;#34;from&amp;#34;:&amp;#34;test@vagrant-centos64&amp;#34;,&amp;#34;to&amp;#34;:&amp;#34;admin@vagrant-centos64&amp;#34;,&amp;#34;subject&amp;#34;:&amp;#34;Restart&amp;#34;,&amp;#34;body&amp;#34;:&amp;#34;In 5 minutes&amp;#34;}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些API将大大增加ejabberd与第三方软件的交互。虽然ejabberd支持&lt;a class="link" href="https://docs.ejabberd.im/developer/ejabberd-api/admin-api/" target="_blank" rel="noopener"&#10; &gt;OAuth认证&lt;/a&gt;，但那是以ejabberd为账户中心的认证，方便其他系统调用ejabberd功能。通常即时通信只是内部系统的一部分，账户中心部署在其他地方，所以需要ejabberd支持外部的认证。前边已经配置ejabberd为数据库认证，还可以配置为使用LDAP认证。如果不满足，还可以配置为&lt;a class="link" href="https://docs.ejabberd.im/admin/configuration/authentication/" target="_blank" rel="noopener"&#10; &gt;外部脚本认证&lt;/a&gt;或者使用第三方开发的&lt;a class="link" href="https://github.com/processone/ejabberd-contrib/tree/master/ejabberd_auth_http" target="_blank" rel="noopener"&#10; &gt;HTTP认证&lt;/a&gt;。对于简单的内部交互，可以将认证服务的token刷新到ejabberd的数据库即可。&lt;br&gt;&#10;&lt;a class="link" href="https://www.igniterealtime.org/projects/openfire/" target="_blank" rel="noopener"&#10; &gt;Openfire&lt;/a&gt;则是ignite realtime出品的Java实现的XMPP服务器，同时提供Java客户端Spark、Java开发库Smack，还提供Chrome扩展&lt;a class="link" href="https://github.com/igniterealtime/Pade" target="_blank" rel="noopener"&#10; &gt;Pade&lt;/a&gt;。Openfire提供基于web的管理界面，支持LDAP登录及数据库存储。有一些功能Openfire并不直接支持，比如API，而是以&lt;a class="link" href="https://igniterealtime.org/projects/openfire/plugins.jsp" target="_blank" rel="noopener"&#10; &gt;扩展&lt;/a&gt;的形式支持，包括用户管理/分组管理/聊天室管理/消息广播/邮件监听/WebSocket/Meeting/Sip等等。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_user.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="774px" data-flex-grow="322" height="93" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_user-300x93.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;用户管理&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_user_group.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="450px" data-flex-grow="187" height="160" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_user_group-300x160.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;配置用户分组，可以配置部门之类的，会出现在用户的个人分组里面（Spark）&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_chat_session_1.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="808px" data-flex-grow="337" height="89" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_chat_session_1-300x89.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;在线会话管理，可以踢人&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_chat_service.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="447px" data-flex-grow="186" height="161" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_chat_service-300x161.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_chat_conference.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="541px" data-flex-grow="225" height="133" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_chat_conference-300x133.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;创建聊天室之前需要创建对应的service，默认的service叫conference。&lt;br&gt;&#10;Openfire的API并不支持OAuth/SSO，简单的1V1消息发送，聊天室消息订阅等等，需要自己基于Java扩展。&lt;br&gt;&#10;Ejabberd是采用Erlang开发的，一如消息队列服务器RabbitMQ，具有极高吞吐能力，提供REST API/XMl RPC，方便交互；Openfire则易于管理和扩展，采用哪个软件进行开发需要结合企业实际进行考量。&lt;br&gt;&#10;XMPP服务器主要提供消息聊天，对于语音服务可以使用SIP服务器实现，结合客户端&lt;a class="link" href="https://sipjs.com/" target="_blank" rel="noopener"&#10; &gt;sip.js&lt;/a&gt;，比如&lt;a class="link" href="https://collecttix.github.io/ctxSip/" target="_blank" rel="noopener"&#10; &gt;ctxSip&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/tcp-udp%e6%8e%a2%e7%b4%a2/" target="_blank" rel="noopener"&#10; &gt;TCP UDP探索&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E5%B0%8D%E8%A9%B1%E5%95%9F%E5%8B%95%E5%8D%94%E5%AE%9A" target="_blank" rel="noopener"&#10; &gt;SIP（会话发起协议）&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>API 网关 Kong</title><link>https://courages.us/api-%E7%BD%91%E5%85%B3-kong/</link><pubDate>Wed, 28 Oct 2020 10:35:51 +0800</pubDate><guid>https://courages.us/api-%E7%BD%91%E5%85%B3-kong/</guid><description>&lt;p&gt;从前开发一个互联网服务程序，大概可以在一台机器上完成：数据库、应用都在一起。随着业务发展壮大，会把数据库独立出来，以便扩展拆分。然后再把一部分公用业务独立出来扩展，譬如文件存储、缓存等。接着业务也才拆分，比如会员、商品。微服务大行其道，各个团队维护着许多服务、API。这么多服务，前端业务逻辑该怎么接入呢？&lt;br&gt;&#10;如今单一的前端UI也可能是多个团队共同开发的结果。当你在本地开发一个小功能时，甚至会牵扯到多个前端UI/后端API。一个前端页面除了加载自己的资源外，还加载V2/V3的API（为什么会同时存在V1/V2/V3的API），甚至嵌入了另外一个页面（React看起来也不错），该怎么调试这种混合开发呢？cookie都传递不过去，好吧，使用&lt;a class="link" href="http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html" target="_blank" rel="noopener"&#10; &gt;JWT&lt;/a&gt;代替，再设置一下&lt;a class="link" href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS" target="_blank" rel="noopener"&#10; &gt;跨源资源共享（CORS）&lt;/a&gt;。。。但是那些旧的应用怎么办？&lt;br&gt;&#10;当我们启动一个Node.js应用时npm run start，默认监听3000端口。当然我们也可以让它监听80端口。但是当我们多开几个应用时，只好让它们都监听不同端口了，怎么样才能统一端口监听呢？当然Node.js可以通过诸如&lt;a class="link" href="https://github.com/http-party/node-http-proxy" target="_blank" rel="noopener"&#10; &gt;node-http-proxy&lt;/a&gt;来转发这些请求，但是代理转发跟应用业务无关吧？如果是其他编程语言呢？都重复这些代理配置/开发吗？Don’t Repeat Yourself。&lt;br&gt;&#10;&lt;a class="link" href="https://www.redhat.com/zh/topics/cloud-native-apps/what-is-faas" target="_blank" rel="noopener"&#10; &gt;Faas&lt;/a&gt;也日渐流行，比如&lt;a class="link" href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&#10; &gt;AWS Lambda&lt;/a&gt;， 强调仅仅专注某个功能，根据事件驱动进行计算，那么每个服务也要开发一整套路由分发/认证/日志吗？&lt;br&gt;&#10;这些问题可以使用反向代理来解决，提供统一的服务入口，对前端/客户端隐藏背后的细节，最简单的当然是Nginx。Nginx监听来自某个端口（比如80）的请求，然后根据不同的来源/端口/域名/url分发给不同的后端服务器。这看起来跟云服务厂商各自开发的负载均衡器差不多，比如&lt;a class="link" href="https://aws.amazon.com/cn/elasticloadbalancing/" target="_blank" rel="noopener"&#10; &gt;AWS ELB&lt;/a&gt;。&lt;br&gt;&#10;在本地开发的时候，我们当然不会使用ELB来解决。直接使用Nginx当然也没啥问题，编辑一下配置文件，重启应用。但是如果有个UI就更好了，如果还有API就非常好了-这样就能方便的在线注册/更改路由而不需要重启服务器，在这个快速发展、弹性开发的年代更需要这个能力。&lt;br&gt;&#10;&lt;a class="link" href="https://konghq.com/kong/" target="_blank" rel="noopener"&#10; &gt;Kong&lt;/a&gt;是一个基于OpenResty的网关服务器，可以进行路由（转发/负载），插件（日志/认证/监控）管理，并提供RESTful API。而&lt;a class="link" href="https://openresty.org/" target="_blank" rel="noopener"&#10; &gt;OpenResty&lt;/a&gt; 是一个基于Nginx与Lua的高性能Web平台，使用Lua来构建动态网关。听起来像是在Nginx上面编程，这跟在Apache上面使用PHP模块进行编程有什么区别？最大的区别在于，这里的编程对象是Nginx（或者公共模块），扩展Nginx能力，比如负载均衡/日志/认证/监控，而不是输出web页面/业务逻辑。这些东西抽出来以后，就不需要每个模块再重复开发了，比如认证/安全。&lt;br&gt;&#10;在本地可以使用docker来运行Kong服务，麻烦在于数据库迁移工作。通常部署Kong需要几个步骤，比如初始化数据库，迁移升级等等。网上的配置大都过时了，这里可以使用官方提供&lt;a class="link" href="https://github.com/Kong/docker-kong/blob/master/compose/docker-compose.yml" target="_blank" rel="noopener"&#10; &gt;docker-compose.yml&lt;/a&gt;来做数据库工作，并且使用&lt;a class="link" href="https://github.com/pantsel/konga" target="_blank" rel="noopener"&#10; &gt;Konga&lt;/a&gt;作为管理UI&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;POSTGRES_PASSWORD data docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong ls data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgresql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong cat POSTGRES_PASSWORD&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kong&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong cat docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;version: &lt;span style="color:#e6db74"&gt;&amp;#39;3.7&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong_data: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong-net:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; external: false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong-migrations:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_DOCKER_TAG&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong:latest&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command: kong migrations bootstrap&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_DATABASE: postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_DATABASE: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_HOST: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart_policy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; condition: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong-migrations-up:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_DOCKER_TAG&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong:latest&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command: kong migrations up &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; kong migrations finish&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_DATABASE: postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_DATABASE: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_HOST: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart_policy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; condition: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_DOCKER_TAG&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong:latest&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user: &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_ADMIN_ACCESS_LOG: /dev/stdout&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_ADMIN_ERROR_LOG: /dev/stderr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_ADMIN_LISTEN: &lt;span style="color:#e6db74"&gt;&amp;#39;0.0.0.0:8001&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_CASSANDRA_CONTACT_POINTS: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_DATABASE: postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_DATABASE: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_HOST: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PROXY_ACCESS_LOG: /dev/stdout&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PROXY_ERROR_LOG: /dev/stderr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;8000:8000/tcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1:8001:8001/tcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;8443:8443/tcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1:8444:8444/tcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; healthcheck:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; test: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;kong&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;health&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval: 10s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout: 10s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; retries: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart_policy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; condition: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; db:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: postgres:9.5&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; POSTGRES_DB: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; POSTGRES_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; POSTGRES_PASSWORD_FILE: /run/secrets/kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; healthcheck:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; test: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_isready&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;-U&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval: 30s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout: 30s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; retries: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart_policy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; condition: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stdin_open: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tty: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - /Users/xxxx/docker/kong/data/postgresql:/var/lib/postgresql/data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; konga:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: pantsel/konga&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TOKEN_SECRET: channing.token&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_ADAPTER: postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_HOST: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_PASSWORD: kong&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_DATABASE: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 1337:1337&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong_postgres_password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file: ./POSTGRES_PASSWORD&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行docker-composer up就可以看到&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;20ebe7885c0d kong:latest &lt;span style="color:#e6db74"&gt;&amp;#34;/docker-entrypoint.…&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago Up &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds &lt;span style="color:#f92672"&gt;(&lt;/span&gt;healthy&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 0.0.0.0:8000-&amp;gt;8000/tcp, 127.0.0.1:8001-&amp;gt;8001/tcp, 0.0.0.0:8443-&amp;gt;8443/tcp, 127.0.0.1:8444-&amp;gt;8444/tcp kong_kong_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4a7a39c863ae pantsel/konga &lt;span style="color:#e6db74"&gt;&amp;#34;/app/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago Up &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds 0.0.0.0:1337-&amp;gt;1337/tcp kong_konga_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aa732758fc51 postgres:9.5 &lt;span style="color:#e6db74"&gt;&amp;#34;docker-entrypoint.s…&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago Up &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds &lt;span style="color:#f92672"&gt;(&lt;/span&gt;health: starting&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 5432/tcp kong_db_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问http://127.0.0.1:1337/即可以进入Konga 管理界面了。8000/8443端口是需要监听转发的端口，8001/8444则是Kong RESTFUl管理API的端口。这里也可以把8000/8443改为80/443，这样访问的时候就可以直接使用域名/localhost而不必加端口了。&lt;br&gt;&#10;注册登录进去后首先要添加Kong RESTFUl管理API的地址，这里使用的是docker环境，IP是动态分配的，所以使用链接名就可以了&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.20.50-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="562px" data-flex-grow="234" height="128" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.20.50-PM-300x128.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;连接上Kong API后可以看到dashboard列出了支持的插件&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-09-29-at-3.57.34-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="545px" data-flex-grow="227" height="132" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-09-29-at-3.57.34-PM-300x132.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;Kong里面的管理对象是service，路由转发/插件都是围绕service展开的，添加一个service&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.27.19-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="433px" data-flex-grow="180" height="166" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.27.19-PM-300x166.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.27.28-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="354px" data-flex-grow="147" height="203" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.27.28-PM-300x203.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;在它上面添加一个路由，这里我们在服务只监听以/api开头的url，并转发到后端服务器去&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.30.37-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="431px" data-flex-grow="179" height="167" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.30.37-PM-300x167.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.30.48-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="260px" data-flex-grow="108" height="276" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.30.48-PM-300x276.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;注意这里在route里面的path里面也需要添加/api，否则转发的时候会出错（多拼api）。最简单就是service监听不指定path，在route里指定。一个service下面可以有多个转发路由，每个可以独立管理、设置超时等。&lt;br&gt;&#10;还可以为每个service绑定不同的插件进行处理，比如认证/安全/日志等等，这样就不用在不同的系统里面重复开发这些功能，使得各个团队更加专注也本业务开发&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.44.18-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="404px" data-flex-grow="168" height="178" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.44.18-PM-300x178.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.45.03-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="365px" data-flex-grow="152" height="197" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.45.03-PM-300x197.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.45.13-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="336px" data-flex-grow="140" height="214" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.45.13-PM-300x214.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;有效插件还可以进行流量限制、请求头/响应头修改等等。这些插件的功能需要基于consumer来开发管理，功能可以非常强大，详细可以参考&lt;a class="link" href="https://github.com/qianyugang/kong-docs-cn/blob/master/HUB/basic-auth.md" target="_blank" rel="noopener"&#10; &gt;文档&lt;/a&gt;。&lt;br&gt;&#10;Kong还有一项功能Upstream配置，与Nginx的&lt;a class="link" href="http://nginx.org/en/docs/http/ngx_http_upstream_module.html" target="_blank" rel="noopener"&#10; &gt;ngx_http_upstream_module&lt;/a&gt;差不多，可以作为负载均衡、流量分发控制使用。可以用命令行测试基于hostname的路由，&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong curl -i -X GET &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --url http://localhost:8000/ &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --header &lt;span style="color:#e6db74"&gt;&amp;#39;Host: dev1.example.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTP/1.1 &lt;span style="color:#ae81ff"&gt;404&lt;/span&gt; Not Found&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Date: Tue, &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; 08:41:58 GMT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Content-Type: application/json; charset&lt;span style="color:#f92672"&gt;=&lt;/span&gt;utf-8&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connection: keep-alive&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Content-Length: &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X-Kong-Response-Latency: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Server: kong/2.1.4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;no Route matched with those values&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt; ➜ kong curl -i -X GET &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --url http://localhost:8000/ &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --header &lt;span style="color:#e6db74"&gt;&amp;#39;Host: dev.example.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTP/1.1 &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; OK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Content-Type: text/html; charset&lt;span style="color:#f92672"&gt;=&lt;/span&gt;UTF-8&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Transfer-Encoding: chunked&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connection: keep-alive&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Date: Tue, &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; 08:42:21 GMT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Server: Apache/2.2.15 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;CentOS&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X-Powered-By: PHP/5.6.40&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Set-Cookie: PHPSESSID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0uc3aoc735j21sk3ni5s72vjc1; path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Expires: Thu, &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; Nov &lt;span style="color:#ae81ff"&gt;1981&lt;/span&gt; 08:52:00 GMT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Cache-Control: no-store, no-cache, must-revalidate, post-check&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0, pre-check&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pragma: no-cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Access-Control-Allow-Credentials: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Access-Control-Allow-Headers: X-CSRF-Token,Authorization,X-Accept-Charset,X-Accept,Content-Type&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X-Kong-Upstream-Latency: &lt;span style="color:#ae81ff"&gt;8397&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X-Kong-Proxy-Latency: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Via: kong/2.1.4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;!DOCTYPE html PUBLIC &lt;span style="color:#e6db74"&gt;&amp;#34;-//W3C//DTD XHTML 1.0 Strict//EN&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;作为一个API网关，Kong能做的很多。如果只是在本地简单的做反向代理，可以使用&lt;a class="link" href="https://github.com/jc21/nginx-proxy-manager" target="_blank" rel="noopener"&#10; &gt;nginx-proxy-manager&lt;/a&gt;，这也是一个基于Nginx开发的网关，根据WEB UI动态生成Nginx配置文件，然后执行/usr/sbin/nginx -s reload生效。有些参数不能通过UI配置（比如超时设置），可以直接写Nginx配置，upstream则支持直接转发tcp请求，支持websockets代理转发，甚至集成了&lt;a class="link" href="https://courages.us/lets-encrypt/" target="_blank" rel="noopener"&#10; &gt;Let’s encrypt&lt;/a&gt;自动申请SSL证书（需要验证域名）&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.03.05-PM.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="576px" data-flex-grow="240" height="125" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.03.05-PM-300x125.jpg" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.10.57-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="217px" data-flex-grow="90" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.10.57-PM-272x300.png" width="272"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.11.47-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="123px" data-flex-grow="51" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.11.47-PM-154x300.png" width="154"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.11.54-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="219px" data-flex-grow="91" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.11.54-PM-274x300.png" width="274"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.13.20-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="666px" data-flex-grow="277" height="108" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.13.20-PM-300x108.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;本地同样可以使用docker跑起来，默认监听80/443端口，81端口即管理界面&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager ls -lah&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; xxxx domain users 192B Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 10:24 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; xxxx domain users 480B Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 09:15 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; xxxx domain users 2.3K Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 09:42 config.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; xxxx domain users 256B Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 09:31 data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; xxxx domain users 740B Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 10:24 docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; xxxx domain users 96B Oct &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; 16:38 letsencrypt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager cat docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;version: &lt;span style="color:#e6db74"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: &lt;span style="color:#e6db74"&gt;&amp;#39;jc21/nginx-proxy-manager:latest&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: always&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Public HTTP Port:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;80:80&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Public HTTPS Port:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;443:443&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Admin Web Port:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;81:81&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# TCP Forward Example:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;8022:8022&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Make sure this config.json file exists as per instructions above:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./config.json:/app/config/production.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./data:/data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./letsencrypt:/etc/letsencrypt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; db:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: jc21/mariadb-aria&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: always&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_ROOT_PASSWORD: &lt;span style="color:#e6db74"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_DATABASE: &lt;span style="color:#e6db74"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_USER: &lt;span style="color:#e6db74"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_PASSWORD: &lt;span style="color:#e6db74"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./data/mysql:/var/lib/mysql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3dd58e9cff1f jc21/nginx-proxy-manager:latest &lt;span style="color:#e6db74"&gt;&amp;#34;/init&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; weeks ago Up &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; days &lt;span style="color:#f92672"&gt;(&lt;/span&gt;healthy&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 0.0.0.0:80-81-&amp;gt;80-81/tcp, 0.0.0.0:443-&amp;gt;443/tcp, 0.0.0.0:8022-&amp;gt;8022/tcp nginx-proxy-manager_app_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;a033151b28ed jc21/mariadb-aria &lt;span style="color:#e6db74"&gt;&amp;#34;/scripts/run.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; weeks ago Up &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; days 3306/tcp nginx-proxy-manager_db_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;nginx-proxy-manager会将配置写在data目录下面，可以直接编辑这些文件，Nginx reload之后便会生效，可以看到这些文件，具体的加载规则参考&lt;a class="link" href="https://nginxproxymanager.com/advanced-config/#custom-nginx-configurations" target="_blank" rel="noopener"&#10; &gt;文档&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager ls data/nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dead_host default_host default_www dummycert.pem dummykey.pem proxy_host redirection_host stream temp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager cat data/nginx/proxy_host/1.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ------------------------------------------------------------&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# dev.example.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ------------------------------------------------------------&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set $forward_scheme http;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set $server &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.14&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set $port 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name dev.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_log /data/logs/proxy_host-1.log proxy;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_connect_timeout 600;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_send_timeout 600;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_read_timeout 600;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;send_timeout 600;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /Login &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass https://login.example.com:443;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /api/v2 &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://192.168.33.14:9070;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /api/v3 &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass https://dev.ops.example.com:443;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /Chat &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass https://dev.ops.example.com:443;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /Catalog &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://192.168.33.1:3000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /static &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://192.168.33.1:3000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /css &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://192.168.33.1:3000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Proxy!&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include conf.d/include/proxy.conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Custom&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /data/nginx/custom/server_proxy&lt;span style="color:#f92672"&gt;[&lt;/span&gt;.&lt;span style="color:#f92672"&gt;]&lt;/span&gt;conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager cat data/nginx/stream/1.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ------------------------------------------------------------&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 8022 TCP: 1 UDP: 0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ------------------------------------------------------------&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 8022;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:8022;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass 192.168.33.14:22;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Custom&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /data/nginx/custom/server_stream&lt;span style="color:#f92672"&gt;[&lt;/span&gt;.&lt;span style="color:#f92672"&gt;]&lt;/span&gt;conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /data/nginx/custom/server_stream_tcp&lt;span style="color:#f92672"&gt;[&lt;/span&gt;.&lt;span style="color:#f92672"&gt;]&lt;/span&gt;conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在docker-compose.yml里面设置一下upstream监听转发的端口，就可以通过8022端口访问192.168.33.14的22端口了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  nginx-proxy-manager telnet 127.0.0.1 &lt;span style="color:#ae81ff"&gt;8022&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Trying 127.0.0.1...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connected to localhost.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Escape character is &lt;span style="color:#e6db74"&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSH-2.0-OpenSSH_5.3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;^C^C^C^C^C^C^CConnection closed by foreign host.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不论是Kong还是nginx-proxy-manager均有提供API，极大的增强服务网关的可编程性，为动态上线/弹性扩展/自动化运维提供了便利。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://aws.amazon.com/cn/blogs/china/iaas-faas-serverless/" target="_blank" rel="noopener"&#10; &gt;从IaaS到FaaS—— Serverless架构的前世今生&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://developer.51cto.com/art/202004/615649.htm" target="_blank" rel="noopener"&#10; &gt;聊一聊微服务网关 Kong&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://cloud.tencent.com/developer/article/1435756" target="_blank" rel="noopener"&#10; &gt;KONG网关 — KongA管理UI使用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://juejin.im/post/6844903924911063053" target="_blank" rel="noopener"&#10; &gt;云原生架构下的 API 网关实践： Kong （二）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://xie.infoq.cn/article/ba0f7503c73b86126017c0d32" target="_blank" rel="noopener"&#10; &gt;微服务 API 网关 -Kong 详解&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://dev.to/bambattajb/creating-an-api-with-lua-using-openresty-42mc" target="_blank" rel="noopener"&#10; &gt;Creating a web API with Lua using Nginx OpenResty&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://cloud.tencent.com/developer/article/1027563" target="_blank" rel="noopener"&#10; &gt;Nginx基于TCP/UDP端口的四层负载均衡（stream模块）配置梳理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.jianshu.com/p/45cb044ba99d" target="_blank" rel="noopener"&#10; &gt;Nginx支持TCP代理和负载均衡-stream模块&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.scienjus.com/api-gateway-and-netflix-zuul/" target="_blank" rel="noopener"&#10; &gt;聊聊 API Gateway 和 Netflix Zuul&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.servicemesher.com/envoy/intro/what_is_envoy.html" target="_blank" rel="noopener"&#10; &gt;Envoy 是什么？&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>短网址生成</title><link>https://courages.us/%E7%9F%AD%E7%BD%91%E5%9D%80%E7%94%9F%E6%88%90/</link><pubDate>Wed, 07 Aug 2019 15:25:04 +0800</pubDate><guid>https://courages.us/%E7%9F%AD%E7%BD%91%E5%9D%80%E7%94%9F%E6%88%90/</guid><description>&lt;p&gt;有时候我们想把一个URL分享给别人，如果URL参数太多，或者太长了，生成的二维码就不好扫描，不方便分享。于是便有了缩短网址的需求，比如微博的t.cn，微信的url.cn，Twitter的t.co。甚至有Bitly.com这样的第三方短网址服务商，提供url访问统计/营销。&lt;br&gt;&#10;怎么样将一个长URL映射成短的URL？如果只是单纯的字符串压缩，很难达到，没办法预计URL有多长。将URL MD5后看起来可行，但是有点长，我们不需要那么多位。最简单的就是在数据库里面存储，一个ID对应一个URL。事实上世界上的URL仍然没有超过2的64次方，因此我们采用自增数字ID就可以了，比如数据库自增量或&lt;a class="link" href="https://courages.us/%e5%9f%ba%e4%ba%8eswoole%e5%92%8czookeeper%e7%9a%84id%e7%94%9f%e6%88%90%e5%99%a8/" target="_blank" rel="noopener"&#10; &gt;分布式ID生成器&lt;/a&gt;。使用自增数字ID的好处是它可以作为数据库主键，通过它来查找对应的URL就很快来。但是随着ID的增长，它也会变得很长，我们还可以将它缩短：将一个10进制的数字转换为62进制的字符串，最多只要11个字符就可以了。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/08/64to62.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="2400px" data-flex-grow="1000" height="30" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/08/64to62-300x30.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/08/64to10.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="2000px" data-flex-grow="833" height="36" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/08/64to10-300x36.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;如果能预计需要生成的网址数量，还可以再缩短，譬如世界上的网址数量大概50亿，62的7次方远大于这个数，因此7个字符足够了。&lt;br&gt;&#10;当访问短网址时，需要301/302重定向到原本的长网址。如果是301永久重定向，则搜索引擎会直接显示重定向后的地址。&lt;br&gt;&#10;PHP函数base_convert可以在2和36进制之间转换，对于62进制就不行，这里分享一个Base62 的转换类，可以将10进制数字转换位62进制&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Conversion&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Base&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BASE_MIN&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BASE_MAX&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;62&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt; $base, &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $aplphabet)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (($base &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BASE_MIN&lt;/span&gt;) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; ($base &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BASE_MAX&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;base convert only require &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BASE_MIN&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; &amp;lt;= base &amp;lt;= &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BASE_MAX&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($aplphabet)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;cannot have empty aplphabet&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($base &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\strlen&lt;/span&gt;($aplphabet)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;base convert only require base &amp;lt;= aplphabet length &amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;base&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $base;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $aplphabet;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;encode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt; $number)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $number &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) $number;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;base&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $reminder &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcmod&lt;/span&gt;($number, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $quotient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcdiv&lt;/span&gt;($number, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt;[$reminder];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($quotient) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $reminder &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcmod&lt;/span&gt;($quotient, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $quotient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcdiv&lt;/span&gt;($quotient, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt;[$reminder] &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $result;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $result;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $number)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;base&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $length &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\strlen&lt;/span&gt;($number);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;\strpos&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt;, $number[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; $length; $i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcadd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;\bcmul&lt;/span&gt;($base, $result), (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;\strpos&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt;, $number[$i]));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)$result;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Base62&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Base&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;parent&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;62&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用a-z表示10-36，A-Z表示37-62。注意这里需要用到&lt;a class="link" href="https://www.php.net/manual/en/book.bc.php" target="_blank" rel="noopener"&#10; &gt;BCMath&lt;/a&gt;扩展，否则对于超过2的32次方的大数字数不准确。也可以使用&lt;a class="link" href="https://www.php.net/manual/en/book.gmp.php" target="_blank" rel="noopener"&#10; &gt;GMP&lt;/a&gt;扩展的gmp_strval函数直接转换。注意gmp使用A-Z表示10-36，a-z表示37-62。&lt;br&gt;&#10;测试一下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/../vendor/autoload.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Conversion\Base62&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$base62 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Base62&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;56800235584&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;; $i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $encode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $base62&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;encode&lt;/span&gt;($id);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $decode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $base62&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;decode&lt;/span&gt;($encode);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $id&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$encode&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$decode&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; $i;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的起始ID可以自定义或者在分布式ID生成器里面更改CUSTOM_EPOCH生成合适的值。&lt;br&gt;&#10;由于这个ID本身就是唯一，映射为固定长度的字符，也可以用来做唯一标识，比如匿名用户的ID，Ngrok三级域名等等。&lt;br&gt;&#10;这个类可以扩展成支持任意2-64进制的转换，更改映射的字符串就行了。&lt;br&gt;&#10;注意这里的Base62转换于PHP函数base64_encode/base64_decode没有任何关系，即使在这个类的基础上增加2个字符支持Base64编码也不一样。&lt;a class="link" href="https://zh.wikipedia.org/wiki/Base64" target="_blank" rel="noopener"&#10; &gt;Base64&lt;/a&gt;是使用64个可打印字符对二进制数据的编码解码，它的编码表与这里定义的不一样。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/soulmachine/system-design/blob/master/cn/tinyurl.md" target="_blank" rel="noopener"&#10; &gt;如何设计一个短网址服务(TinyURL)？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stackoverflow.com/questions/4964197/converting-a-number-base-10-to-base-62-a-za-z0-9" target="_blank" rel="noopener"&#10; &gt;converting a number base 10 to base 62 (a-zA-Z0-9)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://blog.jgrossi.com/2013/generating-ids-like-youtube-or-bit-ly-using-php/" target="_blank" rel="noopener"&#10; &gt;Generating IDs like Youtube or Bit.ly using PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://marcus.bointon.com/php-base-62-encoding/" target="_blank" rel="noopener"&#10; &gt;PHP Base-62 encoding&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.kerstner.at/2012/07/shortening-strings-using-base-62-encoding/" target="_blank" rel="noopener"&#10; &gt;Shortening Strings (URLs) using Base 62 Encoding&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://kennycason.com/posts/2012-10-24-php-base-n-conversion.html" target="_blank" rel="noopener"&#10; &gt;Base 2, 8, 16, 62, N Conversion – PHP&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>基于Swoole和Zookeeper的分布式ID生成器</title><link>https://courages.us/%E5%9F%BA%E4%BA%8Eswoole%E5%92%8Czookeeper%E7%9A%84id%E7%94%9F%E6%88%90%E5%99%A8/</link><pubDate>Sun, 28 Jul 2019 11:48:22 +0800</pubDate><guid>https://courages.us/%E5%9F%BA%E4%BA%8Eswoole%E5%92%8Czookeeper%E7%9A%84id%E7%94%9F%E6%88%90%E5%99%A8/</guid><description>&lt;p&gt;大部分业务都需要一个唯一标识ID，比如订单ID、消息ID，通常使用的ID就是数据库的自增ID，比如MySQL的AUTO_INCREMENT；有时候这个ID还需要在不同系统里面传递、保存，又要保证唯一性。单机MySQL在高并发请求下面又可能存在锁/性能问题，于是&lt;a class="link" href="http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/" target="_blank" rel="noopener"&#10; &gt;Flicker&lt;/a&gt;使用两台MySQL来生成ID，一台从0开始，一台从1开始，步长为2，这样两台生成的ID不会互相重复，这个方案也可以扩展成N台，自增步长为N即可。&lt;br&gt;&#10;作为一个分布式ID应当避免在不同节点同步ID信息，通常都是基于时间戳和机器信息来生成。比如MongoDB的ObjectId是提前生成的为12字节=4字节UNIX时间戳+3字节机器码+2字节进程ID+2字节计数序列。&lt;br&gt;&#10;如果不需要访问数据库即能生成ID，性能可以更高。比如&lt;a class="link" href="https://en.wikipedia.org/wiki/Universally_unique_identifier" target="_blank" rel="noopener"&#10; &gt;UUID V1&lt;/a&gt;，基于时间戳和网卡，采用128位，可以生成范围非常广的ID，但是生成的16进制值的36位字符串不好排序。在MySQL里面可以通过调整机器码（MAC）和时间戳位置顺序，并&lt;a class="link" href="https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/" target="_blank" rel="noopener"&#10; &gt;采用binary来存储以提高性能&lt;/a&gt;。&lt;br&gt;&#10;Twitter开源的&lt;a class="link" href="https://github.com/twitter-archive/snowflake" target="_blank" rel="noopener"&#10; &gt;Snowflake&lt;/a&gt;则生成64位数字ID，包括41时间戳，10位机器码/节点码，12位计数序列，另外1位保留。采用基于时间戳的数字ID的好处是这个ID可以当作主键，并且已经粗略按时间排好序，可以直接分页读取，省去在时间字段上建立索引。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/07/snowflake.jpeg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="705px" data-flex-grow="294" height="102" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/07/snowflake-300x102.jpeg" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;分布式ID通常需要用到机器信息（节点ID或MAC），一个机器通常只运行一个服务进程，所以通常不采用Nginx/Apache + PHP。参考&lt;a class="link" href="https://www.callicoder.com/distributed-unique-id-sequence-number-generator/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;实现一个基于Swoole和Zookpeer的64位ID生成器。基于Swoole可以快速开发一个Web/Socket server，不同于Apache/Nginx，它的PHP进程启动后是常驻运行的，资源初始化后可以重复使用，使用Zookpeer来获取当前进程的节点ID，一旦PHP进程退出后便会销毁对应的节点ID。&lt;br&gt;&#10;首先是生成ID&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Exception\IllegalTimeException&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Number&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TOTAL_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EPOCH_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NODE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SEQUENCE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;MAX_NODE_ID&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;NODE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;MAX_SEQUENCE_NUMBER&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SEQUENCE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CUSTOM_EPOCH&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1262332800000&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $lastTimestamp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $sequence &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $nodeId &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt; $nodeId)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nodeId&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $nodeId;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getNodeId&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nodeId&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getTimestamp&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;) (&lt;span style="color:#a6e22e"&gt;\microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CUSTOM_EPOCH&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;generate&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $current &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getTimestamp&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($current &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lastTimestamp&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;IllegalTimeException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;current timestamp cannot less than before&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($current &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lastTimestamp&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_SEQUENCE_NUMBER&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $current &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_waitNextTimestamp&lt;/span&gt;($current);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lastTimestamp&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $current;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $current &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TOTAL_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;EPOCH_BIT&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getNodeId&lt;/span&gt;() &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TOTAL_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;EPOCH_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;NODE_BIT&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_waitNextTimestamp&lt;/span&gt;($current)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($current &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lastTimestamp&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $current &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getTimestamp&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $current;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里只涉及到ID生成，包括时间戳，序列号获取，而节点ID由其他对象生成并传入。2的42次方减1等于4398046511103，大概就是2109年5月15日，可以使用(2^42-1)/(365*24*60*60*1000)≈139年，距离现在还有90年可以用，仍然是一个非常大的可使用范围。CUSTOM_EPOC是自定义的时间戳偏移量，以便选取合适的ID生成下限和上限。距离现在节点生成的接口定义&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NodeInterface&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;MAX_NODE_ID&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Number&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;NODE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getId&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里定义了最大节点序号不能超过1023，可以依据自己的需求更改范围。节点ID的实现可以是基于网卡/进程ID/文件配置等等实现，但是不同机器或多进程之间需要不一样的ID或者需要锁保证上面的generate函数。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Zookeeper&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Client&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Zookeeper&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makePath&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $path, &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $arrPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\explode&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, $path);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($arrPath)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $arrPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\array_filter&lt;/span&gt;($arrPath);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $subpath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $flag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($arrPath &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $p) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $subpath &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$p;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt;($subpath)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;makeNode&lt;/span&gt;($subpath, $value)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $flag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $flag;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makeNode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $path, &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $value, &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt; $acls &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [], &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt; $flag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($acls)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $acls &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;perms&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PERM_ALL&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;scheme&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;anyone&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;create&lt;/span&gt;($path, $value, $acls, $flag)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deletePath&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $path)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $children &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getChildren&lt;/span&gt;($path);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($children)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($children &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $child) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $subpath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$child;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;deletePath&lt;/span&gt;($subpath);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;delete&lt;/span&gt;($path);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用Zookeeper实现&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Node&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Exception\UnavailableNodeIdException&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\NodeInterface&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Zookeeper\Client&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zookeeper&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NodeInterface&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $zk;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $dsn;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $pool;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $basePath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/dig/ticket&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $acls &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;perms&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PERM_ALL&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;scheme&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;anyone&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $dsn, &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/sim/ticket&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dsn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $dsn;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pool&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\SplQueue&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($path)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $path;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Client&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;zk&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;zk&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Client&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dsn&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;zk&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getId&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;makePath&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $length &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\mb_strlen&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_NODE_ID&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $nodeId &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\sprintf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;%0&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$length&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;, $i);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $children &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getChildren&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $children &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($children) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; [] &lt;span style="color:#f92672"&gt;:&lt;/span&gt; $children;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (; $i &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_NODE_ID&lt;/span&gt;; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;$i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $nodeId &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\sprintf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;%0&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$length&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;, $i);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;\in_array&lt;/span&gt;($nodeId, $children)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$nodeId;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt;($path)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//throw new UnavailableNodeIdException(&amp;#39;node already exist: &amp;#39;.$path);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;makeNode&lt;/span&gt;($path, $nodeId, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;acls&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;\Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;EPHEMERAL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;\ZookeeperException&lt;/span&gt; $e) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//throw new UnavailableNodeIdException(&amp;#39;cannot create node in zookeeper: &amp;#39;.$e-&amp;gt;getMessage());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_NODE_ID&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UnavailableNodeIdException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;cannot create node in zookeeper: reach max node limit &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_NODE_ID&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $i;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里遍历查询1-1023之间的节点是否都已在Zookeeper上注册，如果没有则注册，Zookeeper会保证只有一个客户端注册成功。注册的节点类型位Zookeeper::EPHEMERAL，在客户端退出时，该节点会被自动删除，方便其他机器/进程申请。在&lt;a class="link" href="https://courages.us/php-zookeeper%e5%88%86%e5%b8%83%e5%bc%8f%e6%9c%8d%e5%8a%a1%e5%bc%80%e5%8f%91/" target="_blank" rel="noopener"&#10; &gt;这篇&lt;/a&gt;文章里面我们也使用Zookeeper::EPHEMERAL配合Zookeeper::EPHEMERAL，生成序列号，用来确定进程的master/slave。&lt;br&gt;&#10;初始化并运行Swoole Web server，需要传入Zookeeper的连接字符串，可以使用&lt;a class="link" href="https://hub.docker.com/_/zookeeper" target="_blank" rel="noopener"&#10; &gt;docker&lt;/a&gt;快速部署&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/../vendor/autoload.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Number&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Node\Zookeeper&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZookeeperNode&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/** &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * swoole - zookeeper tick dispatch issue: https://github.com/php-zookeeper/php-zookeeper&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$host &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getenv&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ZOOKEEPER_CONNECTION&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$host &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($host) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.1:2181&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$node &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZookeeperNode&lt;/span&gt;($host);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Swoole\Http\Server&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9501&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;start&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($server) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Swoole http server is started at http://0.0.0.0:9501&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;WorkerStart&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($server, $workerId) &lt;span style="color:#66d9ef"&gt;use&lt;/span&gt;($node) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// https://wiki.swoole.com/wiki/page/325.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// https://wiki.swoole.com/wiki/page/852.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// https://wiki.swoole.com/wiki/page/865.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// use lazy initial zk here, so that each worker can hold its own zk resource&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// if we only run swoole http server in 1 worker process (1 CPU), then no need to consider this&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $node&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getId&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $server&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nodeId&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $server&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Number&lt;/span&gt;($server&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nodeId&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;request&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($request, $response) &lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; ($http) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;generate&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $response&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;end&lt;/span&gt;($data);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;start&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问本机的9501端口即可以得到ID了，完整代码在&lt;a class="link" href="https://github.com/llitllie/dig/tree/master/src/Dig" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。Swoole默认运行与CPU核数量相同的worker进程数，注意这里需要WorkerStart里初始化获取Node节点ID，如果只是运行一个Swoole worker进程，也可以在外面获取节点ID。可以将Swool\Htpp\Server替换成React\Http\Server或者Amp\Http\Server，它们在单个进程里面loop，每个进程分别持有自己的节点序号，可以保证生成的ID不冲突，性能方面Swoole &amp;gt; Amp &amp;gt; ReactPHP。&lt;br&gt;&#10;可以采用Swoole\Server + thrift/gRPC改造这些代码，提供RPC服务。&lt;br&gt;&#10;注意ID的生成是随时间递增的，依赖于时间戳，如果出现了时间回拨，将会抛出异常。一般解决方案包括：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;等待重试&lt;/li&gt;&#10;&lt;li&gt;使用Int64原子自增量代替时间戳，跳过时间戳判断&lt;/li&gt;&#10;&lt;li&gt;使用预留的节点ID&lt;/li&gt;&#10;&lt;li&gt;关闭时钟同步&lt;/li&gt;&#10;&lt;li&gt;使用备选自增量方案&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;生成的ID并不是严格递增的，只是千分一秒递增，对于微博、Twiter的Timeline够用；但也有好处，比如别人不能通过ID相减了解美团的订单量。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/soulmachine/system-design/blob/master/cn/distributed-id-generator.md" target="_blank" rel="noopener"&#10; &gt;如何设计一个分布式ID生成器(Distributed ID Generator)，并保证ID按时间粗略有序？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://mp.weixin.qq.com/s?__biz=MzI4MTY5NTk4Ng==&amp;amp;mid=2247489561&amp;amp;idx=1&amp;amp;sn=7396f373af4efa62ba4dbecc6d7f83b3&amp;amp;source=41#wechat_redirect" target="_blank" rel="noopener"&#10; &gt;生成全局唯一ID的3个思路，来自一个资深架构师的总结&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.slideshare.net/nguyentungniit/distributed-unique-id-generation" target="_blank" rel="noopener"&#10; &gt;Distributed unique id generation&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://preparingforcodinginterview.wordpress.com/2017/03/21/unique-id-generation-in-distributed-systems/" target="_blank" rel="noopener"&#10; &gt;Unique ID generation in distributed systems&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stitcher.io/blog/optimised-uuids-in-mysql" target="_blank" rel="noopener"&#10; &gt;Optimised UUIDs in mysql&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://mysqlserverteam.com/storing-uuid-values-in-mysql-tables/" target="_blank" rel="noopener"&#10; &gt;Storing UUID Values in MySQL Tables&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://mysqlserverteam.com/mysql-8-0-uuid-support/" target="_blank" rel="noopener"&#10; &gt;Mysql 8.0: UUID support&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stackoverflow.com/questions/4444771/how-to-store-a-128-bit-number-in-a-single-column-in-mysql" target="_blank" rel="noopener"&#10; &gt;How to store a 128 bit number in a single column in MySQL?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.callicoder.com/distributed-unique-id-sequence-number-generator/" target="_blank" rel="noopener"&#10; &gt;Generating unique IDs in a distributed environment at high scale&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://tech.meituan.com/2017/04/21/mt-leaf.html" target="_blank" rel="noopener"&#10; &gt;Leaf——美团点评分布式ID生成系统&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.jianshu.com/p/98c202f64652" target="_blank" rel="noopener"&#10; &gt;分布式ID增强篇–优化时钟回拨问题&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/" target="_blank" rel="noopener"&#10; &gt;Ticket Servers: Distributed Unique Primary Keys on the Cheap&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c" target="_blank" rel="noopener"&#10; &gt;Sharding &amp;amp; IDs at Instagram&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Nginx + Frp/Ngrok反向代理Webhook至本地</title><link>https://courages.us/nginx-frp-ngrok%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86webhook%E8%87%B3%E6%9C%AC%E5%9C%B0/</link><pubDate>Wed, 15 May 2019 20:21:20 +0800</pubDate><guid>https://courages.us/nginx-frp-ngrok%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86webhook%E8%87%B3%E6%9C%AC%E5%9C%B0/</guid><description>&lt;p&gt;跟第三方平台打交道，经常需要设置一个接受通知的Webhook，比如微信/Skype的回调。它们要求有一个可以在互联网上访问得了的入口，比如某个域名，如果是在本地开发的话，不好调试。通常使用花生壳来代理本地服务，但是花生壳有一些限制，比如端口。有些域名服务商，比如DNSPOD，Linode，提供相应的API，也可以自己搭建DDNS服务，但是也可能有端口访问限制。&lt;a class="link" href="https://github.com/fatedier/frp" target="_blank" rel="noopener"&#10; &gt;Frp&lt;/a&gt;/&lt;a class="link" href="https://ngrok.com/" target="_blank" rel="noopener"&#10; &gt;Ngrok&lt;/a&gt;都是Go语言开发的内网穿透工具，可以自己部署搭建。Frp是国人开发的一款反向代理软件，可以转发请求给位于NAT后面的机器，支持TCP，UDP，HTTP/HTTPS。Ngrok则是国外的一款内网穿透软件，也支持HTTP/HTTPS转发。这里使用Nginx作为反向代理服务器，接收互联网回调并转发给本地的Frp/Ngrok服务，由它们接收webhook请求并转发至本地开发环境。&lt;br&gt;&#10;前面&lt;a class="link" href="https://courages.us/centos-7%e4%b8%8a%e5%ae%89%e8%a3%85openvpn/" target="_blank" rel="noopener"&#10; &gt;使用OpenVpn搭建了私有网络&lt;/a&gt;，可以在Nginx里面配置转发给目标机器就可以了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim /etc/nginx/conf.d/100-dev.example.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内容如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name dev.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;301&lt;/span&gt; https://$host$request_uri;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 443;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name dev.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_session_cache builtin:1000 shared:SSL:10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_prefer_server_ciphers on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Real-IP $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://10.9.0.2/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_redirect off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用了&lt;a class="link" href="https://courages.us/lets-encrypt/" target="_blank" rel="noopener"&#10; &gt;let’s encryt&lt;/a&gt;的泛域名证书，官方并没有&lt;a class="link" href="https://certbot.eff.org/docs/using.html#dns-plugins" target="_blank" rel="noopener"&#10; &gt;对应的插件&lt;/a&gt;，但是DNSPOD有提供相应的API，第三方开发了一个插件自certbot-dns-dnspod，安装这个插件并且配置Dnspod的API Token：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ yum install certbot python2-certbot-nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ certbot --nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pip install certbot-dns-dnspod&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/letsencrypt/dnspod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot_dns_dnspod:dns_dnspod_email &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;123@163.com&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot_dns_dnspod:dns_dnspod_api_token &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;123,ca440********&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ chmod &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; /etc/letsencrypt/dnspod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;手动请求证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ certbot certonly -a certbot-dns-dnspod:dns-dnspod --certbot-dns-dnspod:dns-dnspod-credentials /etc/letsencrypt/dnspod.conf --server https://acme-v02.api.letsencrypt.org/directory -d example.com -d &lt;span style="color:#e6db74"&gt;&amp;#34;*.example.com&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Saving debug log to /var/log/letsencrypt/letsencrypt.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Plugins selected: Authenticator certbot-dns-dnspod:dns-dnspod, Installer None&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting new HTTPS connection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: acme-v02.api.letsencrypt.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Obtaining a new certificate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Performing the following challenges:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dns-01 challenge &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dns-01 challenge &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting new HTTPS connection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: dnsapi.cn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Waiting &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; seconds &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS changes to propagate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; verification...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Cleaning up challenges&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Resetting dropped connection: acme-v02.api.letsencrypt.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IMPORTANT NOTES:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - Congratulations! Your certificate and chain have been saved at:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /etc/letsencrypt/live/example.com/fullchain.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Your key file has been saved at:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /etc/letsencrypt/live/example.com/privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Your cert will expire on 2019-08-04. To obtain a new or tweaked&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; version of this certificate in the future, simply run certbot&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; again. To non-interactively renew *all* of your certificates, run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;certbot renew&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*/1 * * * * /usr/local/qcloud/stargate/admin/start.sh &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &amp;amp;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - If you like Certbot, please consider supporting our work by:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Donating to ISRG / Let&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;s Encrypt: https://letsencrypt.org/donate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Donating to EFF: https://eff.org/donate-le&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -la /etc/letsencrypt/live/example.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwx------ &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 cert.pem -&amp;gt; ../../archive/example.com/cert1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;35&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 chain.pem -&amp;gt; ../../archive/example.com/chain1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;39&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 fullchain.pem -&amp;gt; ../../archive/example.com/fullchain1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;37&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 privkey.pem -&amp;gt; ../../archive/example.com/privkey1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;692&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 README&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置证书自动更新&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0,12 * * * python -c &lt;span style="color:#e6db74"&gt;&amp;#39;import random; import time; time.sleep(random.random() * 3600)&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; certbot renew&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Frp的开发者已经提供了编译好的&lt;a class="link" href="https://github.com/fatedier/frp/releases" target="_blank" rel="noopener"&#10; &gt;frp服务端和客户端&lt;/a&gt;，下载即可使用。这里使用docker来运行Frp服务，使用这个&lt;a class="link" href="https://hub.docker.com/r/yangliu/frps/dockerfile" target="_blank" rel="noopener"&#10; &gt;Dockerfile&lt;/a&gt;，更改版本号为0.26.0，并编译&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ docker build . -t frps:0.26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ docker images&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REPOSITORY TAG IMAGE ID CREATED SIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;frps 0.26 8a87cb91d4de &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago 21.1MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下SSH代理服务，创建服务端配置文件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p frp/conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim frp/conf/frps.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;frps.ini内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;common&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bind_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行一下frp服务端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#清除先前运行的容器&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ docker rm frp-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ docker run --name frp-server -v /root/frp/conf:/conf -p 7000:7000 -p 6000:6000 frps:0.26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:17 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:136&lt;span style="color:#f92672"&gt;]&lt;/span&gt; frps tcp listen on 0.0.0.0:7000&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:17 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;root.go:204&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Start frps success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:337&lt;span style="color:#f92672"&gt;]&lt;/span&gt; client login info: ip &lt;span style="color:#f92672"&gt;[&lt;/span&gt;110.87.98.82:61894&lt;span style="color:#f92672"&gt;]&lt;/span&gt; version &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0.26.0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; hostname &lt;span style="color:#f92672"&gt;[]&lt;/span&gt; os &lt;span style="color:#f92672"&gt;[&lt;/span&gt;linux&lt;span style="color:#f92672"&gt;]&lt;/span&gt; arch &lt;span style="color:#f92672"&gt;[&lt;/span&gt;386&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tcp.go:66&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt; tcp proxy listen port &lt;span style="color:#f92672"&gt;[&lt;/span&gt;6000&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:398&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt; new proxy &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt; success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:41 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy.go:82&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt; get a new work connection: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;110.*.*.*:61894&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里映射了2个端口，端口7000是frp服务端监听的端口，以便客户端能够连接上；端口6000是需要服务端监听这个端口，以便提供反向代理服务，比如SSH。如果使用的是腾讯云，相应的端口需要在安全组放行。&lt;br&gt;&#10;客户端直接下对应的包，里面有配置试例。创建本地配置文件frpc.ini如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;common&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 123.*.*.*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tcp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local_ip &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 127.0.0.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;remote_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个配置即告诉服务端，将服务端的6000端口转发到本地的22端口。本地运行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ./frpc -c ./frpc.ini.ssh &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:221&lt;span style="color:#f92672"&gt;]&lt;/span&gt; login to server success, get run id &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt;, server udp port &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy_manager.go:137&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt; proxy added: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:144&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt; start proxy success&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在服务端连接客户端。这里连接的是服务端的6000端口，会被转发给远程（局域网内）主机&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;rth@centos72&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ssh -oPort&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6000&lt;/span&gt; vagrant@123.*.*.*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The authenticity of host &lt;span style="color:#e6db74"&gt;&amp;#39;[123.*.*.*]:6000 ([123.*.*.*]:6000)&amp;#39;&lt;/span&gt; can&lt;span style="color:#e6db74"&gt;&amp;#39;t be established.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;RSA key fingerprint is SHA256:NhBO/PDL***********************.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;RSA key fingerprint is MD5:20:70:e2:*:*:*:*:*:*:*:*:*:*:*:*:*.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Are you sure you want to continue connecting (yes/no)? yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Warning: Permanently added &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:6000&lt;span style="color:#e6db74"&gt;&amp;#39; (RSA) to the list of known hosts.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;vagrant@123.*.*.*&amp;#39;&lt;/span&gt;s password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Last login: Mon Apr &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; 06:39:07 &lt;span style="color:#ae81ff"&gt;2019&lt;/span&gt; from 10.0.2.2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;logout&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connection to 123.*.*.* closed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Frp转发http服务很简单。在conf目录下创建配置frps.ini监听本机来自8080端口的HTTP请求&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;common&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bind_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vhost_http_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@VM_1_218_centos frp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# docker run --name frp-server -v /root/frp/conf:/conf -p 7000:7000 -p 8080:8080 frps:0.26&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:28 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:136&lt;span style="color:#f92672"&gt;]&lt;/span&gt; frps tcp listen on 0.0.0.0:7000&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:28 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:178&lt;span style="color:#f92672"&gt;]&lt;/span&gt; http service listen on 0.0.0.0:8080&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:28 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;root.go:204&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Start frps success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:337&lt;span style="color:#f92672"&gt;]&lt;/span&gt; client login info: ip &lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*:56758&lt;span style="color:#f92672"&gt;]&lt;/span&gt; version &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0.26.0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; hostname &lt;span style="color:#f92672"&gt;[]&lt;/span&gt; os &lt;span style="color:#f92672"&gt;[&lt;/span&gt;linux&lt;span style="color:#f92672"&gt;]&lt;/span&gt; arch &lt;span style="color:#f92672"&gt;[&lt;/span&gt;386&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;http.go:72&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; http proxy listen &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; host &lt;span style="color:#f92672"&gt;[&lt;/span&gt;test.example.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; location &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:398&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; new proxy &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:05 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy.go:82&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; get a new work connection: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*:56758&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:05 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy.go:82&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; get a new work connection: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*:56758&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:06 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy.go:82&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; get a new work connection: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*:56758&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后配置Nginx转发请求&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/nginx/conf.d/100-dev.example.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Real-IP $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:8080/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_redirect off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建本地web传教客户端配置frpc.ini，将来自服务器dev.example.com:8080端口的HTTP请求转发至本地80端口&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;common&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 123.*.*.*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; http&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;custom_domains &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dev.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行本地客户端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 frp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./frpc -c ./frpc.ini&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:221&lt;span style="color:#f92672"&gt;]&lt;/span&gt; login to server success, get run id &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt;, server udp port &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy_manager.go:137&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; proxy added: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:144&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; start proxy success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:37 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;E&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:127&lt;span style="color:#f92672"&gt;]&lt;/span&gt; work connection closed, EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:37 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:228&lt;span style="color:#f92672"&gt;]&lt;/span&gt; control writer is closing&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:37 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:127&lt;span style="color:#f92672"&gt;]&lt;/span&gt; try to reconnect to server...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问dev.example.com既可以看到本地web服务器页面。Frp还可以代理其他请求，也有在它基础上二次加工提供基于token认证的转发服务。&lt;br&gt;&#10;Ngrok 2.0以后不再开源，只能使用1.3版本的搭建。这里使用&lt;a class="link" href="https://github.com/hteen/docker-ngrok" target="_blank" rel="noopener"&#10; &gt;docker-ngrok&lt;/a&gt;来构建。Ngrok构建需要SSL证书，复制刚才生成的letsencypt证书并更改server.sh&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git clone https://github.com/hteen/docker-ngrok&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/fullchain.pem myfiles/base.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/fullchain.pem myfiles/fullchain.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/privkey.pem myfiles/privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim server.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set -e&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DOMAIN&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;**None**&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Please set DOMAIN&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exit &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; ! -f &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;MY_FILES&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/bin/ngrokd&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;ngrokd is not build,will be build it now...&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /bin/sh /build.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;MY_FILES&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/bin/ngrokd -tlsKey&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;MY_FILES&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/privkey.pem -tlsCrt&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;MY_FILES&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/fullchain.pem -domain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DOMAIN&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; -httpAddr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;HTTP_ADDR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; -httpsAddr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;HTTPS_ADDR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; -tunnelAddr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;TUNNEL_ADDR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构建Ngrok镜像&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@VM_1_218_centos docker-ngrok&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# docker build -t ngrok:1.3 .&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@VM_1_218_centos docker-ngrok&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# docker images&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REPOSITORY TAG IMAGE ID CREATED SIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ngrok 1.3 dc70190d6377 &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; seconds ago 260MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;frps 0.26 8a87cb91d4de &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago 21.1MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alpine latest cdf98d1859c1 &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; days ago 5.53MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后交叉编译生成Linux/Mac/Windows平台的客户端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rm -rf assets/client/tls/ngrokroot.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/chain.pem assets/client/tls/ngrokroot.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rm -rf assets/server/tls/snakeoil.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/cert.pem assets/server/tls/snakeoil.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rm -rf assets/server/tls/snakeoil.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/privkey.pem assets/server/tls/snakeoil.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ GOOS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;linux GOARCH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;amd64 make release-client&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ GOOS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;windows GOARCH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;amd64 make release-client&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ GOOS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;darwin GOARCH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;amd64 make release-client&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在服务器上运行Ngrok服务，将8090端口请求转发给容器的80端口，并且映射容器的4443端口到服务器的7000端口，以便客户端连接&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@VM_1_218_centos docker-ngrok&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# docker run --name ngrok -e DOMAIN=&amp;#39;example.com&amp;#39; -p 8090:80 -p 8091:443 -p 7000:4443 -v /root/docker-ngrok/myfiles:/myfiles ngrok:1.3 /bin/sh /server.sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;registry&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun&lt;span style="color:#f92672"&gt;]&lt;/span&gt; No affinity cache specified&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.Info:112&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Listening &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; public http connections on &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:80&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.Info:112&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Listening &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; public https connections on &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:443&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.Info:112&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Listening &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; control and proxy connections on &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:4443&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;metrics&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Reporting every &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; seconds&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; New connection from 123.*.*.*:50529&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Waiting to read message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Reading message with length: &lt;span style="color:#ae81ff"&gt;125&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Read message &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Type&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;Auth&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Payload&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Version&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;MmVersion&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;1.7&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;User&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Password&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;OS&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Arch&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;amd64&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;ClientId&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Renamed connection tun:18e8cd42&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;registry&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Registered control with id 1957f20b9b3ce3b76c7d8fc8b16276ed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1957f20b9b3ce3b76c7d8fc8b16276ed&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Writing message: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Type&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;AuthResp&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Payload&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Version&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;MmVersion&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;1.7&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;ClientId&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;1957f20b9b3ce3b76c7d8fc8b16276ed&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Error&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1957f20b9b3ce3b76c7d8fc8b16276ed&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Writing message: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Type&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;ReqProxy&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Payload&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1957f20b9b3ce3b76c7d8fc8b16276ed&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Waiting to read message&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将刚才编译的客户端下载下来，创建grok.cfg，连接服务器的7000端口&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_addr: &lt;span style="color:#e6db74"&gt;&amp;#34;example.com:7000&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;trust_host_root_certs: false&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;指定要监听的域名，及本地web端口&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./ngrok -config&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ngrok.cfg -subdomain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dev &lt;span style="color:#ae81ff"&gt;9010&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ngrok &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Ctrl+C to quit&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Tunnel Status online &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Version 1.7/1.7 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Forwarding http://dev.flexkit.cn -&amp;gt; 127.0.0.1:9010 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Forwarding https://dev.flexkit.cn -&amp;gt; 127.0.0.1:9010 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Web Interface 127.0.0.1:4040 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Conn 2 &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Avg Conn Time 46.84ms &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTP Requests &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------------- &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GET /teams &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; OK &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;请求dev.example.com即可以访问到本机9010端口的web服务。&lt;br&gt;&#10;附：&lt;a class="link" href="https://www.zerotier.com/" target="_blank" rel="noopener"&#10; &gt;ZeroTier&lt;/a&gt;是一个软件定义网络（SDN）软件，可以免费组建私有网络，当然也可以用来转发服务器请求至本地。&lt;/p&gt;&#10;&lt;p&gt;参考链接：：&lt;br&gt;&#10;&lt;a class="link" href="https://www.xncoding.com/2017/12/29/web/ngrok.html" target="_blank" rel="noopener"&#10; &gt;CentOS7搭建ngrok服务器&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/inconshreveable/ngrok" target="_blank" rel="noopener"&#10; &gt;inconshreveable/ngrok&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://hub.docker.com/r/hteen/ngrok/dockerfile" target="_blank" rel="noopener"&#10; &gt;hteen/ngrok&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://fengqi.me/unix/409.html" target="_blank" rel="noopener"&#10; &gt;搭建自己的 Ngrok 服务器, 并与 Nginx 并存&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.lylinux.net/article/2018/9/18/51.html" target="_blank" rel="noopener"&#10; &gt;使用Docker部署Ngrok实现内网穿透&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.v2ex.com/t/394739" target="_blank" rel="noopener"&#10; &gt;Laravel DDNS package，可代替花生壳之类的软件&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.jianshu.com/p/7294cf136b25" target="_blank" rel="noopener"&#10; &gt;通过DNSPod API实现动态域名解析&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://medium.com/@vista8/%E5%80%9F%E5%8A%A9dnspod-api%E5%AE%9A%E6%97%B6%E6%9B%B4%E6%96%B0%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90%E8%8E%B7%E5%8F%96%E6%A0%91%E8%8E%93%E6%B4%BE%E5%85%AC%E7%BD%91ip-1e460651596b" target="_blank" rel="noopener"&#10; &gt;借助dnspod-api定时更新域名解析获取树莓派公网ip&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://latlonworld.com/article/free-wildcard-ssl-with-lets-encrypt.html" target="_blank" rel="noopener"&#10; &gt;使用Let’s Encrypt生成通配符SSL证书&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://blog.sharpbai.com/2017/07/letsencrypt%E4%BD%BF%E7%94%A8dnspod%E9%AA%8C%E8%AF%81%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0%E8%AF%81%E4%B9%A6/" target="_blank" rel="noopener"&#10; &gt;Letsencrypt使用DNSPOD验证自动更新证书&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://tommy.net.cn/2015/02/25/use-dnspod-as-ddns-on-openwrt/" target="_blank" rel="noopener"&#10; &gt;在 OpenWrt 环境下使用 DnsPod 来实现动态域名解析&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.cnblogs.com/kwongtai/p/6903420.html" target="_blank" rel="noopener"&#10; &gt;利用ssh反向代理以及autossh实现从外网连接内网服务器&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-with-ssl-as-a-reverse-proxy-for-jenkins" target="_blank" rel="noopener"&#10; &gt;How To Configure Nginx with SSL as a Reverse Proxy for Jenkins&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>CentOS 7上安装OpenVPN</title><link>https://courages.us/centos-7%E4%B8%8A%E5%AE%89%E8%A3%85openvpn/</link><pubDate>Wed, 17 Apr 2019 16:19:29 +0800</pubDate><guid>https://courages.us/centos-7%E4%B8%8A%E5%AE%89%E8%A3%85openvpn/</guid><description>&lt;p&gt;之前做的一些树莓派机器因为分布分散，不好远程调试，最近看了&lt;a class="link" href="https://www.cyberciti.biz/faq/centos-7-0-set-up-openvpn-server-in-5-minutes/" target="_blank" rel="noopener"&#10; &gt;CentOS 7.0 Set Up OpenVPN Server In 5 Minutes&lt;/a&gt;，决定备份一下。&lt;br&gt;&#10;首先需要有一台公网服务器，比如阿里云、腾讯云服务器，以便这些设备能连接上。阿里云、腾讯云的服务器外部IP并不是直接绑定在你的服务器上的，而是NAT转发到服务器上的，这与Linode不一样，虽然可以方便换IP。查看服务器公网IP，也可以在云管理后台查看&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip a show eth0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dig +short myip.opendns.com @resolver1.opendns.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | awk -F&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;{ print $2}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后是一键安装脚步&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://raw.githubusercontent.com/Angristan/openvpn-install/master/openvpn-install.sh -O centos7-vpn.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x centos7-vpn.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./centos7-vpn.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Welcome to the OpenVPN installer!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The git repository is available at: https://github.com/angristan/openvpn-install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;I need to ask you a few questions before starting the setup.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You can leave the default options and just press enter &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you are ok with them.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;I need to know the IPv4 address of the network interface you want OpenVPN listening to.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Unless your server is behind NAT, it should be your public IPv4 address.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IP address: 10.0.2.15&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;It seems this server is behind NAT. What is its public IPv4 address or hostname?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;We need it &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; the clients to connect to the server.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Public IPv4 address or hostname: 110.*.*.*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Checking &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; IPv6 connectivity...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Your host does not appear to have IPv6 connectivity.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Do you want to enable IPv6 support &lt;span style="color:#f92672"&gt;(&lt;/span&gt;NAT&lt;span style="color:#f92672"&gt;)&lt;/span&gt;? &lt;span style="color:#f92672"&gt;[&lt;/span&gt;y/n&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: n&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What port &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; you want OpenVPN to listen to?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Default: &lt;span style="color:#ae81ff"&gt;1194&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Custom&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 3&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Random &lt;span style="color:#f92672"&gt;[&lt;/span&gt;49152-65535&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Port choice &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1-3&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What protocol &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; you want OpenVPN to use?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;UDP is faster. Unless it is not available, you shouldn&lt;span style="color:#e6db74"&gt;&amp;#39;t use TCP.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 1) UDP&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 2) TCP&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Protocol [1-2]: 1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;What DNS resolvers do you want to use with the VPN?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 1) Current system resolvers (from /etc/resolv.conf)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 2) Self-hosted DNS Resolver (Unbound)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 3) Cloudflare (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 4) Quad9 (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 5) Quad9 uncensored (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 6) FDN (France)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 7) DNS.WATCH (Germany)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 8) OpenDNS (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 9) Google (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 10) Yandex Basic (Russia)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 11) AdGuard DNS (Russia)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;DNS [1-10]: 3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Do you want to use compression? It is not recommended since the VORACLE attack make use of it.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Enable compression? [y/n]: n&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Do you want to customize encryption settings?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Unless you know what you&amp;#39;&lt;/span&gt;re doing, you should stick with the default parameters provided by the script.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Note that whatever you choose, all the choices presented in the script are safe. &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Unlike OpenVPN&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;s defaults&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;See https://github.com/angristan/openvpn-install#security-and-encryption to learn more.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Customize encryption settings? &lt;span style="color:#f92672"&gt;[&lt;/span&gt;y/n&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: n&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Okay, that was all I needed. We are ready to setup your OpenVPN server now.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You will be able to generate a client at the end of the installation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Press any key to &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个脚本省掉了许许多多配置，基本上按照默认一路enter就可以了，唯一需要输入的就是你的公网IP和生成的OpenVPN客户端连接文件名字，比如client.ovpn&lt;br&gt;&#10;然后启动服务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl stop openvpn@server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable openvpn@server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl restart openvpn@server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl status openvpn@server&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看生成的服务器配置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# cat /etc/openvpn/server.conf&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;port &lt;span style="color:#ae81ff"&gt;1194&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proto udp6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dev tun&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user nobody&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;group nobody&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;persist-key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;persist-tun&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;keepalive &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;topology subnet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server 10.8.0.0 255.255.255.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ifconfig-pool-persist ipp.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#client-to-client&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;dhcp-option DNS 1.0.0.1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;dhcp-option DNS 1.1.1.1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;redirect-gateway def1 bypass-dhcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#server-ipv6 fd42:42:42:42::/112&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#tun-ipv6&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push tun-ipv6&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;route-ipv6 2000::/3&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;redirect-gateway ipv6&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dh none&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ecdh-curve prime256v1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tls-crypt tls-crypt.key &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;crl-verify crl.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ca ca.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cert server_Yfej6xnJrDu3vs6K.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;key server_Yfej6xnJrDu3vs6K.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth SHA256&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cipher AES-128-GCM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ncp-ciphers AES-128-GCM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tls-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tls-version-min 1.2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tls-cipher TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;status /var/log/openvpn/status.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;verb &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;10.8.0.0是默认的组网网段，可以改成别的。腾讯云并不支持IPV6，注释掉。push “dhcp-option DNS 1.0.0.1″是推送DNS服务器给客户端。push “redirect-gateway def1 bypass-dhcp”是重定向客户端所有流量到服务器，建议按需添加需要互访的子网段（默认只有10.8.0.0可以互相访问)，否则所有流量重定向，可能会引起连接问题，比如ssh腾讯云服务器公网22端口进不去。Push和Route还有高级应用，建议参考&lt;a class="link" href="https://openvpn.net/community-resources/how-to/" target="_blank" rel="noopener"&#10; &gt;OpenVPN: 2x HOW TO&lt;/a&gt;&lt;br&gt;&#10;查看连接状况。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;journalctl --identifier openvpn -f&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置腾讯云服务器安全组，开放1194端口&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/04/1194incomming.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="1333px" data-flex-grow="555" height="54" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/04/1194incomming-300x54.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/04/1194outcomming.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="1384px" data-flex-grow="576" height="52" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/04/1194outcomming-300x52.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;将刚才生成的client.ovpn下载下来，mac上双击，使用Tunnelblick打开导入即可。但是使用最新的OpenVPN 2.6提示连不上， 报错：tls-crypt unwrap error: packet too short。&lt;br&gt;&#10;在Linux上安装OpenVPN，启动连接&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install openvpn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp client.ovpn /etc/openvpn/client.conf &lt;span style="color:#75715e"&gt;#一定要复制到这里&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openvpn --client --config /etc/openvpn/client.conf &lt;span style="color:#75715e"&gt;#测试一下&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start openvpn@client&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable openvpn@client&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ping 10.8.0.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip route&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果有问题的话，可以查看iptable配置、网络及进程&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /etc/iptables/add-openvpn-rules.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -A INPUT -i tun0 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -A FORWARD -i tun0 -o eth0 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -A INPUT -i eth0 -p udp --dport &lt;span style="color:#ae81ff"&gt;1194&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -t nat -L -n -v &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;net.ipv4.ip_forward&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;netstat -tulpn | grep :1194&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ps aux | grep openvpn&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当再一次运行脚本的时候，会提示是否创建新用户配置，注意不同用户不能共享同一个配置。这里创建的用户可以是支持用户名密码也可以是无账号密码的。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@tc ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./centos7-vpn.sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Welcome to OpenVPN-install!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The git repository is available at: https://github.com/angristan/openvpn-install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;It looks like OpenVPN is already installed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; you want to &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Add a new user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Revoke existing user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 3&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Remove OpenVPN&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 4&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Select an option &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1-4&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;连上OpenVPN服务器都处于同一个网络了，可以使用内部IP访问。现在使用docker来部署OpenVPN服务也很方便，比如&lt;a class="link" href="https://hub.docker.com/r/mdns/rancher-openvpn" target="_blank" rel="noopener"&#10; &gt;rancher-openvpn&lt;/a&gt;，支持LDAP验证。&lt;br&gt;&#10;如果是两个及以上的局域网互通，可以使用&lt;a class="link" href="https://www.openswan.org/" target="_blank" rel="noopener"&#10; &gt;Openswan&lt;/a&gt;建立虚拟网络连接。&lt;br&gt;&#10;更新：发现resin更新成了&lt;a class="link" href="https://www.balena.io/" target="_blank" rel="noopener"&#10; &gt;balena&lt;/a&gt;，免费支持10台设备，并且开放了IOT相关的&lt;a class="link" href="https://www.balena.io/open/docs/getting-started" target="_blank" rel="noopener"&#10; &gt;系统、软件&lt;/a&gt;。&lt;br&gt;&#10;发现一个新的组网服务&lt;a class="link" href="https://www.zerotier.com/" target="_blank" rel="noopener"&#10; &gt;zerotier&lt;/a&gt;，可以快速的创建属于自己的私有网络。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-centos-7" target="_blank" rel="noopener"&#10; &gt;How To Set Up and Configure an OpenVPN Server on CentOS 7&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.linode.com/docs/networking/vpn/tunnel-your-internet-traffic-through-an-openvpn-server/" target="_blank" rel="noopener"&#10; &gt;Tunnel Your Internet Traffic Through an OpenVPN Server&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://wiki.teltonika.lt/view/OpenVPN_configuration_examples" target="_blank" rel="noopener"&#10; &gt;OpenVPN configuration examples&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://help.aliyun.com/knowledge_detail/42521.html" target="_blank" rel="noopener"&#10; &gt;云服务器 ECS Linux CentOS OpenVPN 配置概述&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://yq.aliyun.com/articles/629131" target="_blank" rel="noopener"&#10; &gt;使用OpenVPN搞定远程办公&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.cnblogs.com/huangweimin/articles/7700892.html" target="_blank" rel="noopener"&#10; &gt;使用openvpn打通两个异地网络&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://linuxpitstop.com/install-openswan-and-create-site-to-site-vpn-on-centos-linux/" target="_blank" rel="noopener"&#10; &gt;How To Install Openswan And Create Site-to-Site VPN On CentOS 7&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://blog.convisoappsec.com/setting-up-an-ipsec-vpn-using-openswan-in-cloud-environments/" target="_blank" rel="noopener"&#10; &gt;Setting up an IPSEC VPN using OpenSwan in cloud environments&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://wiki.archlinux.org/index.php/Openswan_L2TP/IPsec_VPN_client_setup" target="_blank" rel="noopener"&#10; &gt;Openswan L2TP/IPsec VPN client setup&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/%e5%9c%a8raspberry-pi%e4%b8%8a%e9%9d%a2%e8%bf%90%e8%a1%8cdocker/" target="_blank" rel="noopener"&#10; &gt;在Raspberry Pi上面运行Docker&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://einverne.github.io/post/2018/06/zerotier.html" target="_blank" rel="noopener"&#10; &gt;使用 Zerotier 组建虚拟局域网实现内网穿透&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://askubuntu.com/questions/612840/adding-route-on-client-using-openvpn" target="_blank" rel="noopener"&#10; &gt;trying to route between two openvpn clients&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://openvpn.net/vpn-server-resources/site-to-site-routing-explained-in-detail/" target="_blank" rel="noopener"&#10; &gt;Site-to-site VPN routing explained in detail&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Let’s encrypt</title><link>https://courages.us/lets-encrypt/</link><pubDate>Sun, 11 Feb 2018 15:21:18 +0800</pubDate><guid>https://courages.us/lets-encrypt/</guid><description>&lt;p&gt;最近域名主机双双到期了，原来的服务商建议域名迁出，于是转移到了Godaddy，过程很顺利。主机迁到了linode，一个是因为它便宜，另一个是因为想给自己的网站加个SSL证书。&lt;br&gt;&#10;首先是服务器环境Apache, PHP, MaraiDB(MySQL)的配置。 &lt;a class="link" href="https://linode.com/docs/getting-started/" target="_blank" rel="noopener"&#10; &gt;linode 创建主机&lt;/a&gt;很简单，点点就好了，然后可以去启动机器，设置SSH访问。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install httpd php php-cli php-mbstring php-pdo php-mysql php-gd php-tidy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动Apache&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start httpd.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable httpd.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后直接访问你的服务器ip，可以看到默认的欢迎界面&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip addr show eth0 | grep inet | awk &lt;span style="color:#e6db74"&gt;&amp;#39;{ print $2; }&amp;#39;&lt;/span&gt; | sed &lt;span style="color:#e6db74"&gt;&amp;#39;s/\/.*$//&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl 1.139.x.x&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CentOS 7目前默认不提供Mysql Server，而是&lt;a class="link" href="https://mariadb.org/" target="_blank" rel="noopener"&#10; &gt;Mariadb&lt;/a&gt;。MySQL的命令行仍然可以使用并兼容， PHP仍然可以使用PDO及MySQL扩展访问它。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install mariadb-server mariadb&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start mariadb&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后设置管理员密码及安全设置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysql_secure_installation&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开机启动Mariadb服务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable mariadb.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以在/var/www/html目录下创建一个测试脚本来验证安装情况&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;phpinfo&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;WordPress则是从原本的数据库全部导出，文件全部打包回来。&lt;br&gt;&#10;在Linode上创建对应的数据库，用户及导入脚本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MariaDB &lt;span style="color:#f92672"&gt;[(&lt;/span&gt;none&lt;span style="color:#f92672"&gt;)]&lt;/span&gt;&amp;gt; CREATE database courages_wordpress;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MariaDB &lt;span style="color:#f92672"&gt;[(&lt;/span&gt;none&lt;span style="color:#f92672"&gt;)]&lt;/span&gt;&amp;gt; CREATE USER courages_wp IDENTIFIED BY &lt;span style="color:#e6db74"&gt;&amp;#39;*************&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MariaDB &lt;span style="color:#f92672"&gt;[(&lt;/span&gt;none&lt;span style="color:#f92672"&gt;)]&lt;/span&gt;&amp;gt; grant all privileges on courages_wordpress.* to courages_wp@localhost identified by &lt;span style="color:#e6db74"&gt;&amp;#39;*************&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;导入数据库&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysql -uroot -p courages_wordpress &amp;lt; /tmp/wordpress.sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将文件解压并复制到/var/www/html目录&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -xzvf backup.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp -R backup/public_html/* /var/www/html/*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chown -R apache:apache /var/www/html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改Apache设置AllowOverride 为all，以便支持WordPress的链接重定向。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim /etc/httpd/conf/httpd.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;Directory &lt;span style="color:#e6db74"&gt;&amp;#34;/var/www/html&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Possible values for the Options directive are &amp;#34;None&amp;#34;, &amp;#34;All&amp;#34;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# or any combination of:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Note that &amp;#34;MultiViews&amp;#34; must be named *explicitly* --- &amp;#34;Options All&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# doesn&amp;#39;t give it to you.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# The Options directive is both complicated and important. Please see&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# http://httpd.apache.org/docs/2.4/mod/core.html#options&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# for more information.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Options Indexes FollowSymLinks&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# AllowOverride controls what directives may be placed in .htaccess files.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# It can be &amp;#34;All&amp;#34;, &amp;#34;None&amp;#34;, or any combination of the keywords:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Options FileInfo AuthConfig Limit&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AllowOverride All&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Controls who can get stuff from this server.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Require all granted&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/Directory&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启Apache&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl restart httpd.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在linode的DNS manager那里新增一个新的domain，在服务器列表里面选中对应的服务器就可以了，然后就可以看到对应的域名解析信息。&lt;br&gt;&#10;域名转移会要求一个key，从原注册商那里解锁并获得，在Godday输入Key后，它会发邮件与你确认，然后将DNS域名服务器改为linode的域名服务器就好了。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://letsencrypt.org/getting-started/" target="_blank" rel="noopener"&#10; &gt;Let’s Encrypt&lt;/a&gt;提供免费90天的SSL证书，如果证书到期了就需要再次更新下。如果你有shell权限，它推荐使用&lt;a class="link" href="https://certbot.eff.org/" target="_blank" rel="noopener"&#10; &gt;Cerbot&lt;/a&gt;来安装和更新证书。CentOS 7 + Apache的安装非常简单。首先安装EPEL源，要不然找不到对应的安装包&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install epel-release&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install certbot-apache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot --authenticator webroot --installer apache&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设置一下域名，网站目录及域名重定向&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Saving debug log to /var/log/letsencrypt/letsencrypt.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Plugins selected: Authenticator webroot, Installer apache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter email address &lt;span style="color:#f92672"&gt;(&lt;/span&gt;used &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; urgent renewal and security notices&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Enter &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &amp;lt;email@example.com&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting new HTTPS connection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: acme-v01.api.letsencrypt.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Please read the Terms of Service at&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;agree in order to register with the ACME server at&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://acme-v01.api.letsencrypt.org/directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;A&lt;span style="color:#f92672"&gt;)&lt;/span&gt;gree/&lt;span style="color:#f92672"&gt;(&lt;/span&gt;C&lt;span style="color:#f92672"&gt;)&lt;/span&gt;ancel: A&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Would you be willing to share your email address with the Electronic Frontier&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Foundation, a founding partner of the Let&lt;span style="color:#e6db74"&gt;&amp;#39;s Encrypt project and the non-profit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;organization that develops Certbot? We&amp;#39;&lt;/span&gt;d like to send you email about EFF and&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;our work to encrypt the web, protect its users and defend digital rights.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;Y&lt;span style="color:#f92672"&gt;)&lt;/span&gt;es/&lt;span style="color:#f92672"&gt;(&lt;/span&gt;N&lt;span style="color:#f92672"&gt;)&lt;/span&gt;o: Y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting new HTTPS connection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: supporters.eff.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;No names were found in your configuration files. Please enter in your domain&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name&lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;comma and/or space separated&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Enter &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Obtaining a new certificate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Performing the following challenges:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http-01 challenge &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input the webroot &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; courages.us: &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Enter &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: /var/www/html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; verification...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Cleaning up challenges&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;We were unable to find a vhost with a ServerName or Address of courages.us.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Which virtual host would you like to choose?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;note: conf files with multiple vhosts are not yet supported&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1: ssl.conf | | HTTPS | Enabled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Press &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;enter&lt;span style="color:#f92672"&gt;]&lt;/span&gt; to confirm the selection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;press &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Deploying Certificate &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; courages.us to VirtualHost /etc/httpd/conf.d/ssl.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1: No redirect - Make no further changes to the webserver configuration.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2: Redirect - Make all requests redirect to secure HTTPS access. Choose this &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;new sites, or &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you&lt;span style="color:#e6db74"&gt;&amp;#39;re confident your site works on HTTPS. You can undo this&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;change by editing your web server&amp;#39;&lt;/span&gt;s configuration.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Select the appropriate number &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1-2&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;enter&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;press &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Created redirect file: le-redirect-courages.us.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rollback checkpoint is empty &lt;span style="color:#f92672"&gt;(&lt;/span&gt;no changes made?&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Congratulations! You have successfully enabled https://courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You should test your configuration at:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://www.ssllabs.com/ssltest/analyze.html?d&lt;span style="color:#f92672"&gt;=&lt;/span&gt;courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在浏览器访问一下域名即有小绿钥匙。可以在/etc/httpd/conf.d/ssl.conf查看相应的SSL证书配置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;VirtualHost _default_:443&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ServerName courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSLCertificateFile /etc/letsencrypt/live/courages.us/cert.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSLCertificateKeyFile /etc/letsencrypt/live/courages.us/privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Include /etc/letsencrypt/options-ssl-apache.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSLCertificateChainFile /etc/letsencrypt/live/courages.us/chain.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/VirtualHost&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于证书在90天后即将失效，可以加入crontab自动更新&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot renew --dry-run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;crontab -e&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0,12 * * * python -c &lt;span style="color:#e6db74"&gt;&amp;#39;import random; import time; time.sleep(random.random() * 3600)&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; certbot renew &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另外一种更新证书的方法是使用&lt;a class="link" href="https://github.com/acmesh-official/acme.sh" target="_blank" rel="noopener"&#10; &gt;acme.sh&lt;/a&gt;，不依赖python，同样支持DNS验证，并且还可以获取其他CA颁发的证书，比如&lt;a class="link" href="https://zerossl.com/" target="_blank" rel="noopener"&#10; &gt;ZeroSSL&lt;/a&gt;。&lt;br&gt;&#10;安装acme。sh脚本非常简单&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ curl https://get.acme.sh | sh -s email&lt;span style="color:#f92672"&gt;=&lt;/span&gt;llitllie@163.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% Total % Received % Xferd Average Speed Time Time Time Current&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Dload Upload Total Spent Left Speed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1032&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1032&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;608&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; --:--:-- 0:00:01 --:--:-- &lt;span style="color:#ae81ff"&gt;608&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% Total % Received % Xferd Average Speed Time Time Time Current&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Dload Upload Total Spent Left Speed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; 216k &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; 216k &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 104k &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0:00:02 0:00:02 --:--:-- 104k&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:22 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Installing from online archive.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:22 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Downloading https://github.com/acmesh-official/acme.sh/archive/master.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:25 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Extracting master.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; It is recommended to install socat first.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; We use socat &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; standalone server &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you use standalone mode.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; If you don&lt;span style="color:#e6db74"&gt;&amp;#39;t use standalone mode, just ignore this warning.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installing to /root/.acme.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installed to /root/.acme.sh/acme.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installing alias to &amp;#39;&lt;/span&gt;/root/.zshrc&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] OK, Close and reopen your terminal to start using acme.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installing alias to &amp;#39;&lt;/span&gt;/root/.cshrc&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installing alias to &amp;#39;&lt;/span&gt;/root/.tcshrc&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Installing cron job&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Good, bash is found, so change the shebang to use bash as preferred.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; OK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Install success!&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里采用DNS验证获取证书，设置一下&lt;a class="link" href="https://github.com/acmesh-official/acme.sh/wiki/dnsapi" target="_blank" rel="noopener"&#10; &gt;DNS厂商信息&lt;/a&gt;，比如DNSPOD，默认获取ZeroSSL证书，可以通过&lt;a class="link" href="https://github.com/acmesh-official/acme.sh/wiki/Change-default-CA-to-ZeroSSL" target="_blank" rel="noopener"&#10; &gt;–server letsencrypt&lt;/a&gt;切换&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ export DP_Id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;95731&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ export DP_Key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;***&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ acme.sh --issue --dns dns_dp -d example.com -d &lt;span style="color:#e6db74"&gt;&amp;#34;*.example.com&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:24 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Using CA: https://acme.zerossl.com/v2/DV90&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:24 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Create account key ok.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:24 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; No EAB credentials found &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ZeroSSL, let&lt;span style="color:#e6db74"&gt;&amp;#39;s get one&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:29 CST] Registering account: https://acme.zerossl.com/v2/DV90&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] Registered&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] ACCOUNT_THUMBPRINT=&amp;#39;&lt;/span&gt;AY5noJZbSullM7fVQOnluxQJmWiiKJHl0vzVsYwwGsg&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] Creating domain key&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] The domain key is here: /root/.acme.sh/example.com_ecc/example.com.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] Multi domain=&amp;#39;&lt;/span&gt;DNS:example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:39 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Getting domain auth token &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; each domain&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:56 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Getting webroot &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; domain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;example.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:56 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Getting webroot &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; domain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;*.example.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:56 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Adding txt value: q-pQccpOPbYbC4h_veQTSvj2OgUpgg9kBUFpms9fa9k &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; domain: _acme-challenge.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:57 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Adding record&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:57 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The txt record is added: Success.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:01 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Let&lt;span style="color:#e6db74"&gt;&amp;#39;s check each DNS record now. Sleep 20 seconds first.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:23 CST] You can use &amp;#39;&lt;/span&gt;--dnssleep&lt;span style="color:#e6db74"&gt;&amp;#39; to disable public dns checks.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:23 CST] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:23 CST] Checking example.com for _acme-challenge.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:23 CST] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:27 CST] Domain example.com &amp;#39;&lt;/span&gt;_acme-challenge.example.com&lt;span style="color:#e6db74"&gt;&amp;#39; success.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:34 CST] All success, let&amp;#39;&lt;/span&gt;s &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:34 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Verifying: example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:46 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Processing, The CA is processing your order, please just wait. &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1/30&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:51 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:51 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Verifying: *.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:55 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Processing, The CA is processing your order, please just wait. &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1/30&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Removing DNS records.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Removing txt: q-pQccpOPbYbC4h_veQTSvj2OgUpgg9kBUFpms9fa9k &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; domain: _acme-challenge.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:30 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Removed: Success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:34 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Verify finished, start to sign.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:35 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Lets finalize the order.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:40 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Order status is processing, lets sleep and retry.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:40 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Retry after: &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:00 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Downloading cert.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:00 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Le_LinkCert&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;https://acme.zerossl.com/v2/DV90/cert/pcAU9PLEoObR7xYPTb9x7w&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Cert success.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----BEGIN CERTIFICATE-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MIIELzCCA7agAwIBAgIRAOO4Gyu...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QRwR2SSrAlEIeJXua7aYyyEEJQ&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----END CERTIFICATE-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Your cert is in: /root/.acme.sh/example.com_ecc/example.com.cer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Your cert key is in: /root/.acme.sh/example.com_ecc/example.com.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The intermediate CA cert is in: /root/.acme.sh/example.com_ecc/ca.cer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; And the full chain certs is there: /root/.acme.sh/example.com_ecc/fullchain.cer&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后安装证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ acme.sh --install-cert -d example.com -d &lt;span style="color:#e6db74"&gt;&amp;#34;*.example.com&amp;#34;&lt;/span&gt;--key-file /etc/letsencrypt/live/example.com/privkey.pem --fullchain-file /etc/letsencrypt/live/example.com/chain.pem --reloadcmd &lt;span style="color:#e6db74"&gt;&amp;#34;systemctl restart nginx&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The domain &lt;span style="color:#e6db74"&gt;&amp;#39;example.com&amp;#39;&lt;/span&gt; seems to have a ECC cert already, lets use ecc cert.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Installing key to: /etc/letsencrypt/live/example.com/privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Installing full chain to: /etc/letsencrypt/live/example.com/chain.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Run reload cmd: systemctl restart nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Reload success&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以后就可以自动更新了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ crontab -l | grep acme &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; * * * &lt;span style="color:#e6db74"&gt;&amp;#34;/root/.acme.sh&amp;#34;&lt;/span&gt;/acme.sh --cron --home &lt;span style="color:#e6db74"&gt;&amp;#34;/root/.acme.sh&amp;#34;&lt;/span&gt; &amp;gt; /dev/null&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最近登录后台发现WordPress提示&lt;a class="link" href="https://wordpress.org/support/update-php/" target="_blank" rel="noopener"&#10; &gt;升级到PHP 7.3&lt;/a&gt;，按照它的指示&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;使用&lt;a class="link" href="https://wordpress.org/plugins/updraftplus/" target="_blank" rel="noopener"&#10; &gt;UpdraftPlus&lt;/a&gt;备份网站和数据库，支持Google Drive, Dropbox&lt;/li&gt;&#10;&lt;li&gt;使用&lt;a class="link" href="https://wordpress.org/plugins/php-compatibility-checker/" target="_blank" rel="noopener"&#10; &gt;PHP Compatibility Checker&lt;/a&gt;检测代码及扩展是否支持升级到PHP 7.3&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;在CentOS 7上升级PHP5.4 到PHP 7.3很简单：&lt;br&gt;&#10;首先安装Remi和EPEL仓库&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install wget&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpm -Uvh remi-release-7.rpm &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpm -Uvh epel-release-latest-7.noarch.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install yum-utils&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启用remi-php73的源，yum update升级会自动升级PHP及扩展&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# yum-config-manager --enable remi-php73&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# yum repolist&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loaded plugins: fastestmirror&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loading mirror speeds from cached hostfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * base: mirrors.linode.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * epel: kartolo.sby.datautama.net.id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * extras: mirrors.linode.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * remi-php73: mirror.xeonbd.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * remi-safe: mirror.xeonbd.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * updates: mirrors.linode.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;repo id repo name status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;base/7/x86_64 CentOS-7 - Base 10,019&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;epel/x86_64 Extra Packages &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Enterprise Linux &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; - x86_64 13,051&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extras/7/x86_64 CentOS-7 - Extras &lt;span style="color:#ae81ff"&gt;385&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;remi-php73 Remi&lt;span style="color:#e6db74"&gt;&amp;#39;s PHP 7.3 RPM repository for Enterprise Linux 7 - x86_64 305&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;remi-safe Safe Remi&amp;#39;&lt;/span&gt;s RPM repository &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Enterprise Linux &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; - x86_64 3,188&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;updates/7/x86_64 CentOS-7 - Updates 1,511&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;repolist: 28,825&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum update -y&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查PHP版本，重启Apache&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# php -v&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP 7.3.4 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;cli&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;built: Apr &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2019&lt;/span&gt; 13:48:50&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt; NTS &lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Copyright &lt;span style="color:#f92672"&gt;(&lt;/span&gt;c&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 1997-2018 The PHP Group&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Zend Engine v3.3.4, Copyright &lt;span style="color:#f92672"&gt;(&lt;/span&gt;c&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 1998-2018 Zend Technologies&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# systemctl restart httpd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以禁用对应PHP版本的源，选择性升级PHP到对应版本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum-config-manager --disable remi-php72&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;顺便升级下php-mcrypt和ZipArchive&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install php-mcrypt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install php-pecl-zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-centos-7#step-two-%E2%80%94-install-mysql-%5c%28mariadb%5c%29" target="_blank" rel="noopener"&#10; &gt;How To Install Linux, Apache, MySQL, PHP (LAMP) stack On CentOS 7&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.liquidweb.com/kb/enable-epel-repository/" target="_blank" rel="noopener"&#10; &gt;How to enable EPEL repository?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://linode.com/docs/security/securing-your-server/" target="_blank" rel="noopener"&#10; &gt;How to Secure Your Server&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://linode.com/docs/security/firewalls/introduction-to-firewalld-on-centos/" target="_blank" rel="noopener"&#10; &gt;Introduction to FirewallD on CentOS&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.mysterydata.com/upgrade-php-5-6-php-7-2-centos-vesta-cp/" target="_blank" rel="noopener"&#10; &gt;How to Upgrade PHP 5.6 to PHP 7.2 on CentOS VestaCP&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Python使用Kerberos认证查询Impala</title><link>https://courages.us/kerberous%E8%AE%A4%E8%AF%81/</link><pubDate>Sun, 22 Oct 2017 11:52:19 +0800</pubDate><guid>https://courages.us/kerberous%E8%AE%A4%E8%AF%81/</guid><description>&lt;p&gt;最近做QoS报告，数据来源于&lt;a class="link" href="https://impala.apache.org/" target="_blank" rel="noopener"&#10; &gt;Impala&lt;/a&gt;，客户端认证采用的是Kerberos。&lt;br&gt;&#10;Impala是&lt;a class="link" href="https://www.cloudera.com/" target="_blank" rel="noopener"&#10; &gt;Cloudera&lt;/a&gt;公司开发并开源的一款基于HDFS/Hbase的MPP SQL引擎，它提供SQL语义，能够查询存储在Hadoop的HDFS和HBase中的PB级大数据。&lt;a class="link" href="https://web.mit.edu/kerberos/" target="_blank" rel="noopener"&#10; &gt;Kerberous&lt;/a&gt;本身是一个网络认证授权协议，借由中心服务器认证，对通信双方的客户端/服务端进行授权而不需要传递双方的密码。Kerberos的认证流程比较有意思，分为&lt;a class="link" href="https://zh.wikipedia.org/wiki/Kerberos" target="_blank" rel="noopener"&#10; &gt;三个阶段&lt;/a&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;客户端认证&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;1 客户端发送自己用户名&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;2 认证服务器返回使用客户端密钥加密的Client/TGS会话密钥和使用票据授权服务器密钥加密的TGT， 包括sessions key，用户信息及有效期&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;3 客户端使用自己的密钥解密出Client/TGS会话密钥&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;服务授权&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;1 客户端发送两条消息：接收到的TGT和所请求的服务ID；使用Client/TGS会话密钥加密的用户ID和时间戳&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;2 票据授权服务器使用自己的密钥解密TGT得到客户端的Client/TGS会话密钥，然后使用它解密出用户ID并进行认证。返回使用所请求服务端密钥加密的client-server票据和使用Client/TGS会话密钥加密的Client/Server会话密钥&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;3 客户端使用Client/TGS会话密钥(Client/TGS Session Key)解密出Client/Server会话密钥&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;服务请求&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;1 客户端发送两条消息：使用所请求服务端密钥加密的client-server票据及使用Client/Server会话密钥加密的用户ID和时间戳&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;2 服务端使用自己的密钥解密client-server票据从而得到Client/Server会话密钥，使用该密钥解密获得用户信息并认证。返回使用Client/Server会话密钥的新时间戳&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;3 客户端使用Client/Server会话密钥解密该消息，认证结束并请求服务&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;4 服务端提供服务&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;在CentOS上安装Kerberos&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install krb5-devel pam_krb5 krb5-libs krb5-workstation&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑配置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim /etc/krb5.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置KDC，认证服务器&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;logging&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FILE:/var/log/krb5libs.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kdc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FILE:/var/log/krb5kdc.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;admin_server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FILE:/var/log/kadmind.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;libdefaults&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_realm &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dns_lookup_realm &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dns_lookup_kdc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ticket_lifetime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 24h&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;renew_lifetime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 7d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forwardable &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_tkt_enctypes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rc4-hmac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_tgs_enctypes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rc4-hmac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;permitted_enctypes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rc4-hmac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;realms&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EXAMPLE.COM &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_domain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kdc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kdc01.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kdc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kdc02.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;admin_server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; adc01.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;admin_server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; adc02.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;domain_realm&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.example.com &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;example.com &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost rc&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# kinit abc.xyz@EXAMPLE.COM&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Password &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; abc.xyz@EXAMPLE.COM:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意这个配置文件每行前面的空格被删掉，是因为在VirtualBox里面每行开头有莫名其妙的乱码，Linux下并不可见，在EditPlus下面才发现，否则会乱报错&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kinit: Improper format of Kerberos configuration file &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; initializing Kerberos &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; library&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kinit: Cannot find KDC &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; realm &lt;span style="color:#e6db74"&gt;&amp;#34;EXAMPLE.COM&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; getting initial credentials&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看一下认证的ticket&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost vagrant&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# klist&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Ticket cache: FILE:/tmp/krb5cc_0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Default principal: abc.xyz@EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Valid starting Expires Service principal&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;09/21/2017 08:30:50 09/21/2017 18:30:50 krbtgt/EXAMPLE.COM@EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; renew &lt;span style="color:#66d9ef"&gt;until&lt;/span&gt; 09/28/2017 08:30:42&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个ticket在28号就会过期了，到时候又要输入密码，这样也不便于自动化程序使用。可以使用ktutil创建&lt;a class="link" href="https://kb.iu.edu/d/aumh" target="_blank" rel="noopener"&#10; &gt;keytab文件&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ktutil&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ktutil: addent -password -p abc.xyz@EXAMPLE.COM -k &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; -e RC4-HMAC&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Password &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; abc.xyz@EXAMPLE.COM:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ktutil: wkt abc.xyz.keytab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ktutil: q&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;abc.xyz.keytab&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kinit -kt abc.xyz.keytab abc.xyz@EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ klist -k abc.xyz.keytab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Keytab name: FILE:abc.xyz.keytab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KVNO Principal&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---- --------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; abc.xyz@EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后便可以使用kinit自动更新ticket了。注意，如果更换了密码，需要重新生成新的keytab。&lt;br&gt;&#10;另外，相同用户生成的授权ticket在任意一台机器上都是相同的， kinit时会自动同步回来的。&lt;br&gt;&#10;公司的大数据平台使用&lt;a class="link" href="http://gethue.com/" target="_blank" rel="noopener"&#10; &gt;Hue&lt;/a&gt;来提供基于web界面的查询，Impala也支持使用ODBC方式查询。在Python里使用的是&lt;a class="link" href="https://github.com/cloudera/impyla" target="_blank" rel="noopener"&#10; &gt;impyla&lt;/a&gt;来查询，首先安装sasl的依赖&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install libgsasl-devel cyrus-sasl-devel cyrus-sasl-gssapi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip install impyla thrift_sasl&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试脚本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; impala.dbapi &lt;span style="color:#f92672"&gt;import&lt;/span&gt; connect&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; connect(host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;impalad.example.com&amp;#34;&lt;/span&gt;, port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;21050&lt;/span&gt;, auth_mechanism&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;GSSAPI&amp;#39;&lt;/span&gt;, kerberos_service_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;impala&amp;#39;&lt;/span&gt;, database&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;acme&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cur &lt;span style="color:#f92672"&gt;=&lt;/span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cursor()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cur&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;SELECT * FROM acme WHERE dt=&amp;#34;2017-09-12&amp;#34; LIMIT 5&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(cur&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fetchall())&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python test.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如下报错，则是服务器不能连接，检查一下网络，DNS/hosts及VPN&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thriftpy.transport.TTransportException: TTransportException&lt;span style="color:#f92672"&gt;(&lt;/span&gt;type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1, message&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Could not connect to (&amp;#39;impalad.example.com&amp;#39;, 21050)&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如下报错，CentOS则是需要cyrus-sasl-gssapi模块&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thriftpy.transport.TTransportException: TTransportException&lt;span style="color:#f92672"&gt;(&lt;/span&gt;type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1, message&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Could not start SASL: b&amp;#39;Error in sasl_client_start (-4) SASL(-4): no mechanism available: No worthy mechs found&amp;#39;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.parallellabs.com/2013/08/25/impala-big-data-analytics/" target="_blank" rel="noopener"&#10; &gt;Impala：新一代开源大数据分析引擎&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ywnds.com/?p=9404" target="_blank" rel="noopener"&#10; &gt;大数据时代快速SQL引擎-Impala&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000002532307" target="_blank" rel="noopener"&#10; &gt;CDH 5.2中Impala认证集成LDAP和Kerberos&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://help.ubuntu.com/community/Kerberos" target="_blank" rel="noopener"&#10; &gt;Kerberos&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.simba.com/products/Impala/doc/JDBC_InstallGuide/content/jdbc/hi/kerberos.htm" target="_blank" rel="noopener"&#10; &gt;Configuring Kerberos Authentication for Windows&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.knime.com/blog/speaking-kerberos-with-knime-big-data-extensions" target="_blank" rel="noopener"&#10; &gt;Speaking Kerberos with KNIME Big Data Extensions&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>使用Supervisor 管理监控进程</title><link>https://courages.us/%E4%BD%BF%E7%94%A8superviosr-%E7%AE%A1%E7%90%86%E7%9B%91%E6%8E%A7%E8%BF%9B%E7%A8%8B/</link><pubDate>Sat, 30 Sep 2017 09:38:29 +0800</pubDate><guid>https://courages.us/%E4%BD%BF%E7%94%A8superviosr-%E7%AE%A1%E7%90%86%E7%9B%91%E6%8E%A7%E8%BF%9B%E7%A8%8B/</guid><description>&lt;p&gt;&lt;a class="link" href="http://supervisord.org/introduction.html" target="_blank" rel="noopener"&#10; &gt;Supervisor&lt;/a&gt;是用Python写的一款应用程监控管理工具，能够启动，停止，重启死进程，提供web管理界面，XML-RPC接口及事件监听。通常我们写了一些脚本都不会带有daemon功能，而是加&amp;amp;或者nohub，screen什么的丢到后台去运行，同时使用corntab定时检测脚本是否存活，以便重新运行脚本。使用Supervisor可以将这些脚本，程序转为守护进程，自动重启它们；还可以监控机器的进程运行状况，输出警报等。&lt;br&gt;&#10;Supervisor只能运行于Python 2.x的环境，但子进程可以为其他任意程序，比如Python 3，PHP等。这里使用pip来安装&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ wget https://bootstrap.pypa.io/get-pip.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ python -V&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo python get-pip.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo pip install supervisor&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成配置文件及日志目录&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo echo_supervisord_conf &amp;gt; /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mkdir /var/log/supervisor&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ chmod &lt;span style="color:#ae81ff"&gt;655&lt;/span&gt; /var/log/supervisor&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动supervisord&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo supervisord -c /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisorctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ Server requires authentication&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ Username:user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ Password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisor&amp;gt; status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisor&amp;gt; help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default commands &lt;span style="color:#f92672"&gt;(&lt;/span&gt;type help &amp;lt;topic&amp;gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=====================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;add exit open reload restart start tail&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;avail fg pid remove shutdown status update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clear maintail quit reread signal stop version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisor&amp;gt; quit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里没有任何进程。以下为常用命令：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;supervisorctl stop program 停止某个进程&lt;/li&gt;&#10;&lt;li&gt;supervisorctl start program 启动某个进程&lt;/li&gt;&#10;&lt;li&gt;supervisorctl restart program 重启某个进程&lt;/li&gt;&#10;&lt;li&gt;supervisorctl stop group 重启属于group分组的所有进程(start,restart同理)&lt;/li&gt;&#10;&lt;li&gt;supervisorctl stop all 停止全部进程，注：start、restart、stop都不会载入最新的配置文件&lt;/li&gt;&#10;&lt;li&gt;supervisorctl reload 载入最新配置文件，停止原有进程并按新配置启动进程&lt;/li&gt;&#10;&lt;li&gt;supervisorctl update 根据最新配置文件，启动新配置或有改动的进程，没有改动的进程不受影响&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;编辑supervisord.conf启用web界面，账号密码为web及supervisorctl共用，必须更改&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vim /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#取消以下行的注释&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;inet_http_server&lt;span style="color:#f92672"&gt;]&lt;/span&gt; ; inet &lt;span style="color:#f92672"&gt;(&lt;/span&gt;TCP&lt;span style="color:#f92672"&gt;)&lt;/span&gt; server disabled by default&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;*:9002 ; ip_address:port specifier, *:port &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; all iface&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;username&lt;span style="color:#f92672"&gt;=&lt;/span&gt;user ; default is no username &lt;span style="color:#f92672"&gt;(&lt;/span&gt;open server&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;password&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt; ; default is no password &lt;span style="color:#f92672"&gt;(&lt;/span&gt;open server&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#添加新应用qrd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;program:qrd&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;directory &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /home/qrd/qrd/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autostart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autorestart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;startsecs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;startretries &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stdout_logfile &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /var/log/supervisor/qrd.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stderr_logfile &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /var/log/supervisor/qrd.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启使HTTP配置生效&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ps aux | grep supervisord &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisord -c /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关于supervisord.conf配置项，命令释义可以参考&lt;a class="link" href="http://zhangweide.cn/archive/2013/supervisor-note.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;command 为要运行的脚本或程序&lt;/li&gt;&#10;&lt;li&gt;directory 为脚本或程序运行时的工作目录&lt;/li&gt;&#10;&lt;li&gt;user 为脚本或程序运行时的用户&lt;/li&gt;&#10;&lt;li&gt;autostart 随supervisord启动&lt;/li&gt;&#10;&lt;li&gt;startsecs 启动后等待时间，过了这个时间没起来就重新启动&lt;/li&gt;&#10;&lt;li&gt;startretries 启动失败后重试的次数&lt;/li&gt;&#10;&lt;li&gt;stdout_logfile，stderr_logfile 为输出日志&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;重新加载所有应用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisorctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Server requires authentication&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Username:user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisor&amp;gt; reload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Really restart the remote supervisord process y/N? y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Restarted supervisord&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisor&amp;gt; status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrd RUNNING pid 3861, uptime 0:00:22&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到定义的qrd程序已经起来了。如果qrd程序意外退出了，那么supervisord将会重启它。如果杀掉了supervisord，那么qrd对应的进程也将被杀死。也可以去web界面查看http://127.0.0.1:9002/&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2017/09/supervisor04.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="705px" data-flex-grow="294" height="102" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2017/09/supervisor04-300x102.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;可以通过web页面来启动，停止进程，查看日志等。&lt;br&gt;&#10;再增加下&lt;a class="link" href="https://github.com/celery/celery/tree/master/extra/supervisord" target="_blank" rel="noopener"&#10; &gt;Celery的Worker，Beat配置&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#f92672"&gt;==================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; celery worker supervisor example&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#f92672"&gt;==================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;program:qrdworker&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Set full path to celery program &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; using virtualenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/celery worker -A qrd --loglevel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;INFO&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Alternatively,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;celery --app&lt;span style="color:#f92672"&gt;=&lt;/span&gt;your_app.celery:app worker --loglevel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;INFO -n worker.%%h&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Or run a script&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;celery.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;directory&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/qrd/qrd/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nobody&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;numprocs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stdout_logfile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/log/supervisor/qrdworker.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stderr_logfile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/log/supervisor/qrdworker.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autostart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autorestart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;startsecs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Need to wait &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; currently executing tasks to finish at shutdown.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Increase this &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you have very long running tasks.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stopwaitsecs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Causes supervisor to send the termination signal &lt;span style="color:#f92672"&gt;(&lt;/span&gt;SIGTERM&lt;span style="color:#f92672"&gt;)&lt;/span&gt; to the whole process group.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stopasgroup&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Set Celery priority higher than default &lt;span style="color:#f92672"&gt;(&lt;/span&gt;999&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; so, &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; rabbitmq is supervised, it will start first.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;priority&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#f92672"&gt;================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; celery beat supervisor example&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#f92672"&gt;================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;program:qrdbeat&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Set full path to celery program &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; using virtualenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/celery -A qrd beat -l info -s /tmp/celerybeat-schedule&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; remove the -A myapp argument &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you aren&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;t using an app instance&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;directory&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/qrd/qrd/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nobody&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;numprocs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stdout_logfile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/log/supervisor/beat.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stderr_logfile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/log/supervisor/beat.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autostart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autorestart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;startsecs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Causes supervisor to send the termination signal &lt;span style="color:#f92672"&gt;(&lt;/span&gt;SIGTERM&lt;span style="color:#f92672"&gt;)&lt;/span&gt; to the whole process group.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stopasgroup&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; rabbitmq is supervised, set its priority higher&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; so it starts first&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;priority&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;999&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后启用它们&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisor&amp;gt; update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrdbeat: added process group&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisor&amp;gt; status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrd RUNNING pid 4468, uptime 0:03:49&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrdbeat BACKOFF Exited too quickly &lt;span style="color:#f92672"&gt;(&lt;/span&gt;process log may have details&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrdworker RUNNING pid 4469, uptime 0:03:49&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看下进程&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo ps aux | grep python&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;1038&lt;/span&gt; 0.0 3.1 &lt;span style="color:#ae81ff"&gt;562392&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15720&lt;/span&gt; ? Ssl 01:49 0:01 /usr/bin/python -Es /usr/sbin/tuned -l -P&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3992&lt;/span&gt; 0.1 3.0 &lt;span style="color:#ae81ff"&gt;222124&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15224&lt;/span&gt; ? Ss 03:49 0:00 /bin/python /bin/supervisord -c /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3993&lt;/span&gt; 0.3 3.8 &lt;span style="color:#ae81ff"&gt;211868&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19296&lt;/span&gt; ? S 03:49 0:00 /usr/local/python3/bin/python3.6 /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3996&lt;/span&gt; 0.3 6.9 &lt;span style="color:#ae81ff"&gt;264048&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34780&lt;/span&gt; ? S 03:49 0:00 /usr/local/python3/bin/python3.6 /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3998&lt;/span&gt; 0.3 6.9 &lt;span style="color:#ae81ff"&gt;264056&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34784&lt;/span&gt; ? S 03:49 0:00 /usr/local/python3/bin/python3.6 /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3999&lt;/span&gt; 0.4 6.9 &lt;span style="color:#ae81ff"&gt;264024&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34784&lt;/span&gt; ? S 03:49 0:00 /usr/local/python3/bin/python3.6 /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;4014&lt;/span&gt; 0.0 0.1 &lt;span style="color:#ae81ff"&gt;112660&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;976&lt;/span&gt; pts/0 R+ 03:50 0:00 grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除了program标签，Supervisor也支持group标签，用来启动一系列的program，比如先启动数据库，再启动web服务器。&lt;br&gt;&#10;Supervisor也可以用来管理PHP进程，比如&lt;a class="link" href="https://blog.tanteng.me/2017/01/supervisor-laravel-queue/" target="_blank" rel="noopener"&#10; &gt;使用 Supervisor 管理 Laravel 队列进程&lt;/a&gt;。&lt;br&gt;&#10;Docker官方推荐一个docker容器只运行一个服务，如果你想启动多个脚本或程序，可以&lt;a class="link" href="https://docs.docker.com/engine/admin/multi-service_container/" target="_blank" rel="noopener"&#10; &gt;使用Supervisor会更简单点&lt;/a&gt;。&lt;br&gt;&#10;如果需要Supervisor开启启动，可以使用&lt;a class="link" href="https://github.com/Supervisor/initscripts" target="_blank" rel="noopener"&#10; &gt;GitHub上的脚本和配置&lt;/a&gt;。CentOS 7上可以配置为service，由systemctl来管理：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vim /etc/systemd/system/supervisord.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内容如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# supervisord service for systemd (CentOS 7.0+)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# by ET-CS (https://github.com/ET-CS)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Unit&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Description&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Supervisor daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Service&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;forking&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecStart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/supervisord&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecStop&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/supervisorctl $OPTIONS shutdown&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecReload&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/supervisorctl $OPTIONS reload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KillMode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Restart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RestartSec&lt;span style="color:#f92672"&gt;=&lt;/span&gt;42s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Install&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WantedBy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;multi-user.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后启用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo systemctl enable supervisord.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Created symlink from /etc/systemd/system/multi-user.target.wants/supervisord.service to /etc/systemd/system/supervisord.service.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo systemctl start supervisord.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo ps aux | grep python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然supervisorctl及web界面都只能管理本机，但是Supervisor提供了&lt;a class="link" href="http://supervisord.org/api.html" target="_blank" rel="noopener"&#10; &gt;XML-RPC接口&lt;/a&gt;，可以获取进程运行信息，因此诞生了许多&lt;a class="link" href="http://supervisord.org/plugins.html" target="_blank" rel="noopener"&#10; &gt;监控平台&lt;/a&gt;，以便监控服务器集群的进程的运行状况。&lt;br&gt;&#10;Supervisor还提供了&lt;a class="link" href="http://supervisord.org/events.html" target="_blank" rel="noopener"&#10; &gt;event listener配置&lt;/a&gt;，在这里Supervisor将会通知脚本其他进程的运行状态变更的事件，可以用来发送警报监控等。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://idoall.org/blog/post/lion/10" target="_blank" rel="noopener"&#10; &gt;使用Supervisor3.2.1基于Mac10.10.3对系统进程进行管理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.jianshu.com/p/eeeedc69b560" target="_blank" rel="noopener"&#10; &gt;supervisor的配置浅析&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.restran.net/2015/10/04/supervisord-tutorial/" target="_blank" rel="noopener"&#10; &gt;Python 进程管理工具 Supervisor 使用教程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.do1618.com/archives/342" target="_blank" rel="noopener"&#10; &gt;Supervisor进程监护使用指南&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000000606682" target="_blank" rel="noopener"&#10; &gt;supervisord 的 XML-RPC API 使用说明&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://chenjiehua.me/linux/supervisor-event-listenser.html" target="_blank" rel="noopener"&#10; &gt;Supervisor Event Listener&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.tothenew.com/blog/dockerizing-nginx-and-ssh-using-supervisord/" target="_blank" rel="noopener"&#10; &gt;Dockerizing Nginx and SSH using Supervisord&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP MongoDB Replica Set应用</title><link>https://courages.us/php-mongodb-replica-set%E5%BA%94%E7%94%A8/</link><pubDate>Sat, 23 Sep 2017 16:10:53 +0800</pubDate><guid>https://courages.us/php-mongodb-replica-set%E5%BA%94%E7%94%A8/</guid><description>&lt;p&gt;&lt;a class="link" href="https://www.mongodb.com/" target="_blank" rel="noopener"&#10; &gt;MongoDB&lt;/a&gt;是个面向文档管理的NoSQL数据库，能够直接存取JSON数据，支持海量数据。公司内部的一个单点登录系统使用MongoDB来存储用户的session，以便在不同应用，服务器之间共享登录信息，解决了服务器切换用户状态丢失（被登出）的问题。单点登录系统前端采用PHP，与&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E8%BD%BB%E5%9E%8B%E7%9B%AE%E5%BD%95%E8%AE%BF%E9%97%AE%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;LDAP&lt;/a&gt;交互认证用户信息，提供登录界面，API等。MongoDB则采用Replica Set模式以便支持高可用。&lt;br&gt;&#10;在CentOS 6.5上安装MongoDB，首先添加源仓库&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ suod vim /etc/yum.repos.d/mongodb.repo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;mongodb&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;MongoDB Repository&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;baseurl&lt;span style="color:#f92672"&gt;=&lt;/span&gt;http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gpgcheck&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;enabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装，启动，连接MongoDB&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo yum --enablerepo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mongodb install mongodb-org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo /sbin/chkconfig --levels &lt;span style="color:#ae81ff"&gt;235&lt;/span&gt; mongod on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo mongod --port &lt;span style="color:#ae81ff"&gt;27017&lt;/span&gt; --dbpath /data/db1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mongo --port &lt;span style="color:#ae81ff"&gt;27017&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建用户SSOReplUser&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; use admin &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; db.createUser&lt;span style="color:#f92672"&gt;(&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; user: &lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplUser&amp;#34;&lt;/span&gt;, pwd: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;password&amp;gt;&amp;#34;&lt;/span&gt;, roles: &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; role: &lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;, db: &lt;span style="color:#e6db74"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;})&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建集群要用到的key&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo openssl rand -base64 &lt;span style="color:#ae81ff"&gt;741&lt;/span&gt; &amp;gt; /home/sso/mongodb-keyfile &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo chmod &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; /home/sso/mongodb-keyfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑MongoDB配置文件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vim /etc/mongod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Replication Options &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# in replicated mongo databases, specify the replica set name here &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;replSet&lt;span style="color:#f92672"&gt;=&lt;/span&gt;SSOReplSet &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# maximum size in megabytes for replication operation log &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#oplogSize=1024 &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# path to a key file storing authentication info for connections # between replica set members keyFile=/home/sso/mongodb-keyfile&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启mongod服务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo /etc/init.d/mongod stop &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo /usr/bin/mongod -f /etc/mongod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用SSOReplUser登录&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; use admin &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; db.auth&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplUser&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;password&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;初始化集群&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; rs.initiate&lt;span style="color:#f92672"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; rs.conf&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplSet&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: 1,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;members&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;: 1,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;host&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.10:27017&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在其他机器上按照上面步骤安装MongoDB，更改配置，复制对应的mongodb-keyfile并启动。&lt;br&gt;&#10;回到192.168.33.10并添加机器&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; rs.add&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.11:27017&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; rs.add&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.12:27017&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; rs.add&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.13:27017&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SSOReplSet:PRIMARY&amp;gt; rs.remove(&amp;#34;192.168.33.13:27017&amp;#34;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在从机上认证查看&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:SECONDARY&amp;gt; use admin &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:SECONDARY&amp;gt; db.auth&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplUser&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;password&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:SECONDARY&amp;gt; rs.status&lt;span style="color:#f92672"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;MongoDB的Replica set模式最少要求3台机器，以便在PRIMARY机器故障时，能够自我选举出新的PRIMARY,但需要n/2+1的机器投票同意。例如刚才配置了4台机器，那么需要4/2+1=3台机器投票，能够承受一台机器故障。如果是集群有5台机器，则能够承受2台机器故障。因此再配置一台不存储数据的&lt;a class="link" href="https://docs.mongodb.com/manual/tutorial/add-replica-set-arbiter/" target="_blank" rel="noopener"&#10; &gt;Arbiter机器&lt;/a&gt;比较合理。&lt;br&gt;&#10;按照上面的步骤安装，复制mongodb-keyfile文件，但需要更改mongod.conf&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sudo vim /etc/mongod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nojournal&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后启动mongod服务并在PRIMARY机器上将这台机器加入机器&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; use admin &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; db.auth&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplUser&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;password&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; rs.addArb&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;ip of arbiter&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP的mongo扩展安装比较简单，下载对应版本，启用即可。然而在应用过程中发现登录有点慢，启用看PHP mongo扩展&lt;a class="link" href="http://php.net/manual/en/mongodb.setprofilinglevel.php" target="_blank" rel="noopener"&#10; &gt;profiling功能&lt;/a&gt;，查看PHP日志&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;\MongoLog&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setLevel&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;\MongoLog&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;\MongoLog&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setModule&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;\MongoLog&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;aaa01(primary)&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $m &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\MongoClient&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;mongodb://admin:XXXXXXXXX@192.168.33.10:27017/?replicaSet=SSOReplSet &amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;aaa01(primay), bbb01(secondary),ccc01(secondary),ddd01(secondary)&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $m &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\MongoClient&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;mongodb://admin:XXXXXXXXX@192.168.33.10:27017,192.168.33.11:27017,192.168.33.12:27017,192.168.33.13:27017/?replicaSet=SSOReplSet &amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;\MongoConnectionException&lt;/span&gt; $e) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($e);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;发现PHP连接MongoDB集群是这样子的&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2017/09/%e6%97%a7%e5%90%8e%e5%8f%b0.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="300px" data-flex-grow="125" height="240" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2017/09/旧后台-300x240.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;即：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1）在连接里面配置了几个MongoDB连接服务器，PHP每个都会创建连接去查询&lt;/li&gt;&#10;&lt;li&gt;2）从每台服务器上查询出整个集群的服务器列表，再分别ping和连接这些服务器，如果连接不存在或不匹配则创建，无效的则销毁&lt;/li&gt;&#10;&lt;li&gt;3）汇总所有服务器返回集群列表&lt;/li&gt;&#10;&lt;li&gt;4）选择离自己最近的服务器并使用该与该服务器的连接&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;MongoDB 的写操作默认在Primary节点上操作完成即返回成功；读操作默认是也是从Primary上读取，所以需要去查询服务器。由于SSO应用部署在多个数据中心，网络抖动会造成较大影响，跨数据中心的查询并不会很快，如果每次都去连接并查询整个列表是比较耗时。另外如果在php里面配置的是IP而MongoDB Replica Set里面配置的是域名，则连接名会出现不匹配，而创建新的连接并销毁旧连接，也耗时。如果配置的是域名，则需要DNS解析。由于每台PHP服务器均已配置HA检测，最终每个应用只配置了一台服务器，并统一配置MongoDB集群为IP。而连接最快的是在Primary机器上，可以根据本机是否Primary来做HA：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/usr/bin/env bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;ps -fe |grep &lt;span style="color:#e6db74"&gt;&amp;#34;mongod&amp;#34;&lt;/span&gt; | grep -v &lt;span style="color:#e6db74"&gt;&amp;#34;grep&amp;#34;&lt;/span&gt; | wc -l&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FILE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/home/scripts-bits/master.conf&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SERVER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;hostname&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; $count -lt &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rm -f $FILE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PRIMAY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;/usr/bin/mongo &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;SERVER&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:27017 --quiet --eval &lt;span style="color:#e6db74"&gt;&amp;#39;printjson(db.isMaster().ismaster);&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$PRIMAY&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; ! -f &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$FILE&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&#9;touch &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$FILE&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;REMOVE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;/usr/bin/mongo &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;SERVER&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:27017/admin --quiet /home/scripts-bits/mongo_status.js&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;删除故障节点(not reachable/healthy)的脚本mongo_status.js:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;auth&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;password&amp;gt;&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;conf&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;status&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;members&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;conf&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;members&amp;#34;&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;members&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;members&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#34;state&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;rs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;remove&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;members&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这中间也出现过因为网络/机器故障，导致PHP等待连接超时的情况的，将该机器从集群中移除即可。然而当服务器是启动的（可以到达）情况下，MongoDB故障，则不会超时。可以更改connectTimeoutMS，以便减少等待。&lt;br&gt;&#10;MongoDB的日志默认都是记录在/var/log/mongodb/下面并且会越来越大。创建Python脚本来定时清除它：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/env python&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; commands&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;,&lt;/span&gt;time&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rotate_log&lt;/span&gt;(path, expire &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; str_now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strftime(&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dat_now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strptime(str_now, &lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; array_dat_now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime(dat_now[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], dat_now[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;], dat_now[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;])&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lns &lt;span style="color:#f92672"&gt;=&lt;/span&gt; commands&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getoutput(&lt;span style="color:#e6db74"&gt;&amp;#34;/bin/ls --full-time &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;|awk &amp;#39;{print $6, $9}&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; path)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ln &lt;span style="color:#f92672"&gt;in&lt;/span&gt; lns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;split(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ws &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ln&lt;span style="color:#f92672"&gt;.&lt;/span&gt;split()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; len(ws) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ws1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strptime(ws[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], &lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ws2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime(ws1[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], ws1[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;], ws1[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;])&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (array_dat_now &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ws2)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;days &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; expire:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; v_del &lt;span style="color:#f92672"&gt;=&lt;/span&gt; commands&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getoutput(&lt;span style="color:#e6db74"&gt;&amp;#34;/bin/rm -rf &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (path, ws[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rotate_mongo&lt;/span&gt;():&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# get mongo pid&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mongo_pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; commands&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getoutput(&lt;span style="color:#e6db74"&gt;&amp;#34;/sbin/pidof mongod&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#print mongo_pid&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# send Sig to mongo&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; mongo_pid &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/bin/kill -USR1 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (mongo_pid)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# print cmd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mongo_rotate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; commands&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getoutput(cmd)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print &lt;span style="color:#e6db74"&gt;&amp;#34;mongod is not running...&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; log_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/var/log/mongodb/&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; expire &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rotate_mongo()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rotate_log(log_path, expire)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加入到crontab里面去执行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; * * * /usr/bin/python /home/sso/mongo_rotate.py &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考连接&lt;br&gt;&#10;&lt;a class="link" href="http://www.jianshu.com/p/7a41907a1549" target="_blank" rel="noopener"&#10; &gt;mongodb与mysql相比的优缺点&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/mongo.connecting.rs.php" target="_blank" rel="noopener"&#10; &gt;PHP MongoDB 复制集合&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/replication/" target="_blank" rel="noopener"&#10; &gt;MongoDB Replication&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/tutorial/enable-authentication/" target="_blank" rel="noopener"&#10; &gt;MongoDB Enable Auth&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/tutorial/rotate-log-files/" target="_blank" rel="noopener"&#10; &gt;MongoDB Rotate Log Files&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://jira.mongodb.org/browse/PHPC-723" target="_blank" rel="noopener"&#10; &gt;Blocking connect() leads to cumulative timeouts for multiple inaccessible servers&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.slideshare.net/profyclub_ru/3-how-raft-consensus-algorithm-will-make-replication-even-better-in-mongo-db-32-henrik-ingo-mongodb" target="_blank" rel="noopener"&#10; &gt;How Raft consensus algorithm will make replication even better in MongoDB 3.2&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/core/replica-set-write-concern/" target="_blank" rel="noopener"&#10; &gt;Write Concern for Replica Sets&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/core/read-preference/" target="_blank" rel="noopener"&#10; &gt;MongoDB Read Preference&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Vagrant CentOS 共享目录挂载问题解决</title><link>https://courages.us/vagrant-centos-%E5%85%B1%E4%BA%AB%E7%9B%AE%E5%BD%95%E6%8C%82%E8%BD%BD%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/</link><pubDate>Sun, 17 Sep 2017 10:07:01 +0800</pubDate><guid>https://courages.us/vagrant-centos-%E5%85%B1%E4%BA%AB%E7%9B%AE%E5%BD%95%E6%8C%82%E8%BD%BD%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/</guid><description>&lt;p&gt;一直以来都是使用Vagrant与VirtualBox运行CentOS系统来搭建环境，然而有一天突然出现Windows下面的目录无法映射进去了，报错:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;D:&lt;span style="color:#ae81ff"&gt;\p&lt;/span&gt;roject&lt;span style="color:#ae81ff"&gt;\v&lt;/span&gt;agrant&lt;span style="color:#ae81ff"&gt;\c&lt;/span&gt;entos64php56&amp;gt;vagrant up&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Bringing machine &lt;span style="color:#e6db74"&gt;&amp;#39;default&amp;#39;&lt;/span&gt; up with &lt;span style="color:#e6db74"&gt;&amp;#39;virtualbox&amp;#39;&lt;/span&gt; provider...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Clearing any previously set forwarded ports...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Clearing any previously set network interfaces...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Preparing network interfaces based on configuration...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Adapter 1: nat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Adapter 2: hostonly&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Forwarding ports...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;guest&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;host&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;adapter 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;guest&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; &lt;span style="color:#ae81ff"&gt;2222&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;host&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;adapter 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Booting VM...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; machine to boot. This may take a few minutes...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH address: 127.0.0.1:2222&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH username: vagrant&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH auth method: private key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Warning: Connection reset. Retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Warning: Connection aborted. Retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Warning: Connection reset. Retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Warning: Remote connection disconnect. Retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Machine booted and ready!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;default&lt;span style="color:#f92672"&gt;]&lt;/span&gt; GuestAdditions versions on your host &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5.1.26&lt;span style="color:#f92672"&gt;)&lt;/span&gt; and guest &lt;span style="color:#f92672"&gt;(&lt;/span&gt;4.3.6&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; not matc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loaded plugins: fastestmirror&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Setting up Install Process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loading mirror speeds from cached hostfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * base: mirrors.btte.net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * epel: repo.fedoralinux.ir&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * extras: mirrors.btte.net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * updates: mirrors.btte.net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;No package kernel-devel-2.6.32-358.23.2.el6.x86_64 available.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package gcc-4.4.7-18.el6.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package binutils-2.20.51.0.2-5.47.el6_9.1.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package 1:make-3.81-23.el6.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package 4:perl-5.10.1-144.el6.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package bzip2-1.0.5-7.el6_0.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Nothing to &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Copy iso file C:&lt;span style="color:#ae81ff"&gt;\P&lt;/span&gt;rogram Files&lt;span style="color:#ae81ff"&gt;\O&lt;/span&gt;racle&lt;span style="color:#ae81ff"&gt;\V&lt;/span&gt;irtualBox&lt;span style="color:#ae81ff"&gt;\V&lt;/span&gt;BoxGuestAdditions.iso into the box&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installing Virtualbox Guest Additions 5.1.26 - guest version is 4.3.6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Verifying archive integrity... All good.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Uncompressing VirtualBox 5.1.26 Guest Additions &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Linux...........&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VirtualBox Guest Additions installer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Removing installed version 5.1.26 of VirtualBox Guest Additions...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Stopping VirtualBox Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Copying additional installer modules ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installing additional modules ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Starting the VirtualBox Guest Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Failed to set up service vboxadd, please check the log file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/var/log/VBoxGuestAdditions.log &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; details.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;An error occurred during installation of VirtualBox Guest Additions 5.1.26. Some func&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;In most cases it is OK that the &lt;span style="color:#e6db74"&gt;&amp;#34;Window System drivers&amp;#34;&lt;/span&gt; installation failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Starting the VirtualBox Guest Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: failed: Look at /var/log/vboxadd-install.log to find out what went wrong.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: failed: modprobe vboxguest failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Checking &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; guest additions in VM...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: The guest additions on this VM &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; not match the installed version of&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: VirtualBox! In most cases this is fine, but in rare cases it can&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: prevent things such as shared folders from working properly. If you see&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: shared folder errors, please make sure the guest additions within the&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: virtual machine match the version of VirtualBox you have installed on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: your host and reload your VM.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Guest Additions Version: 4.3.6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: VirtualBox Version: 5.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Configuring and enabling network interfaces...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH address: 127.0.0.1:2222&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH username: vagrant&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH auth method: private key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Mounting shared folders...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: /home/rc &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; D:/project/vagrant/centos64php56&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Vagrant was unable to mount VirtualBox shared folders. This is usually&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;because the filesystem &lt;span style="color:#e6db74"&gt;&amp;#34;vboxsf&amp;#34;&lt;/span&gt; is not available. This filesystem is&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;made available via the VirtualBox Guest Additions and kernel module.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Please verify that these guest additions are properly installed in the&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;guest. This is not a bug in Vagrant and is usually caused by a faulty&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Vagrant box. For context, the command attempted was:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mount -t vboxsf -o uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;500,gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; home_rc_ /home/rc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The error output from the command was:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/sbin/mount.vboxsf: mounting failed with the error: No such device&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里提示虚拟机里CentOS的VBoxGuestAdditions与VirtualBox的版本匹配，需要升级：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;default&lt;span style="color:#f92672"&gt;]&lt;/span&gt; GuestAdditions versions on your host &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5.1.26&lt;span style="color:#f92672"&gt;)&lt;/span&gt; and guest &lt;span style="color:#f92672"&gt;(&lt;/span&gt;4.3.6&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; not matc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应该是升级了VirtualBox导致的。然而自动安装新插件失败:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Starting the VirtualBox Guest Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Failed to set up service vboxadd, please check the log file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/var/log/VBoxGuestAdditions.log &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; details.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;An error occurred during installation of VirtualBox Guest Additions 5.1.26. Some func&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;In most cases it is OK that the &lt;span style="color:#e6db74"&gt;&amp;#34;Window System drivers&amp;#34;&lt;/span&gt; installation failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Starting the VirtualBox Guest Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: failed: Look at /var/log/vboxadd-install.log to find out what went wrong.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: failed: modprobe vboxguest failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;导致共享目录无法映射。但是虚拟机仍然是启动成功的，可以ssh进去，或者使用sftp挂载。&lt;br&gt;&#10;Google了下有说是&lt;a class="link" href="https://gist.github.com/fernandoaleman/5083680" target="_blank" rel="noopener"&#10; &gt;VirtualBox bug&lt;/a&gt;的，也有说是Windows问题的，各种折腾不能解决。升级插件也无效：vagrant plugin install vagrant-vbguest。重新安装VirtualBox和Vagrant，并不会影响现有虚拟机及网络配置，但不能解决问题。&lt;br&gt;&#10;直到看到&lt;a class="link" href="https://urouge.me/share-folder-mount-error-in-virtualbox/" target="_blank" rel="noopener"&#10; &gt;这篇文章&lt;/a&gt;，决定从CentOS入手解决。&lt;br&gt;&#10;启动虚拟机后，使用sftp上传VBoxGuestAdditions.iso，ssh进入手动安装：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mount VBoxGuestAdditions.iso -o loop /mnt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd /mnt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sh VBoxLinuxAdditions.run&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装失败，查看日志：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Building the main Guest Additions module &lt;span style="color:#f92672"&gt;[&lt;/span&gt;FAILED&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;Look at /var/log/vboxadd-install.log to find out what went wrong&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;vboxadd-install.log日志：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/tmp/vbox.0/Makefile.include.header:97: *** Error: unable to find the sources of your current Linux kernel. Specify KERN_DIR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;lt;directory&amp;gt; and run Make again. Stop.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参照&lt;a class="link" href="https://www.centos.org/forums/viewtopic.php?t=45163" target="_blank" rel="noopener"&#10; &gt;这篇文章&lt;/a&gt;，查看kernel版本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rpm -qa kernel&lt;span style="color:#ae81ff"&gt;\*&lt;/span&gt; | sort&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel-2.6.32-358.23.2.el6.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel-devel-2.6.32-696.10.2.el6.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel-firmware-2.6.32-358.10.2.el6.noarch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel-headers-2.6.32-696.10.2.el6.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ uname -r&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2.6.32-358.10.2.el6.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实一开始是更多版本不匹配的，尝试更新kernel:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install kernel-headers kernel-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果部分更新失败：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Warning: No matches found &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: kernel-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;No Matches found&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参照&lt;a class="link" href="https://stackoverflow.com/questions/29396322/warning-no-matches-found-for-kernel-devel" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;解除版本锁定，设置enabled = 0：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/yum/pluginconf.d/versionlock.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再次运行升级kernel就可以了。安装成功后，重启后，再次运行sh VBoxLinuxAdditions.run 就可以了。事实上Vagrant启动时就会自动安装VBoxGuestAdditions：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;default&lt;span style="color:#f92672"&gt;]&lt;/span&gt; GuestAdditions 5.1.26 running --- OK.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Vagrant升级到后发现vagrant up初始化下载box卡住了，那是你的vagrant版本太高与对应的powershell版本对应不上，可以下载最新的powershell安装即可。&lt;br&gt;&#10;如果box下载很慢，可以参照&lt;a class="link" href="https://urouge.me/how-to-download-vagrant-boxes/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;的方法自我映射取得url单独下载：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://app.vagrantup.com/box-cutter/boxes/centos73&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; https://atlas.hashicorp.com/box-cutter/boxes/centos73/versions/2.0.21/providers/virtualbox.box&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/Varying-Vagrant-Vagrants/VVV/issues/714" target="_blank" rel="noopener"&#10; &gt;Guest Additions Version error on VirtualBox5&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://urouge.me/share-folder-mount-error-in-virtualbox/" target="_blank" rel="noopener"&#10; &gt;VirtualBox下挂载共享文件目录问题处理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://codingbeauty.wordpress.com/2015/10/13/resolving-guestadditions-version-mismatch-in-vagranthomestead-vm-failed-to-mount-shared-folders-modprobe-vboxsf-failed/" target="_blank" rel="noopener"&#10; &gt;Resolving GuestAdditions version mismatch in vagrant/homestead vm (failed to mount shared folders / modprobe vboxsf failed)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.centos.org/forums/viewtopic.php?t=45163" target="_blank" rel="noopener"&#10; &gt;Problem installing virtualBox guest additions&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stackoverflow.com/questions/29396322/warning-no-matches-found-for-kernel-devel" target="_blank" rel="noopener"&#10; &gt;Warning: No matches found for: kernel-devel&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/hashicorp/vagrant/issues/8777" target="_blank" rel="noopener"&#10; &gt;Vagrant up hangs forever on Windows 7, Vagrant 1.9.7, VirtualBox 5.1.22.r11512&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>TCP UDP探索</title><link>https://courages.us/tcp-udp%E6%8E%A2%E7%B4%A2/</link><pubDate>Sat, 03 Dec 2016 16:19:12 +0800</pubDate><guid>https://courages.us/tcp-udp%E6%8E%A2%E7%B4%A2/</guid><description>&lt;p&gt;最近开发新接口，为实现更高的性能，深入考察了下TCP，UDP通信协议。之前的开发当中都是基于HTTP的接口开发，简单易用，各个编程语言都支持；web服务器、中间件成熟，方便扩展；支持安全加密等等。与自定义Socket通信相比，HTTP仍然不够高效。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;TCP协议&lt;/a&gt;，也叫传输控制协议（Transmission Control Protocol）是一种面向连接的、可靠的、基于字节流的传输层通信协议。每建立一个TCP连接需要三次握手，关闭时又需要四次握手；传输过程当中，每发送一个包，都要接收一个确认回复，如果在一定时间内未收到，则重发，如果是同一块数据分包传输，则回复所需要的包序号；在发送和接收时都要计算校验和。由于有严格的数据包传输顺序和校验，因为接收到的数据将会是顺序。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E7%94%A8%E6%88%B7%E6%95%B0%E6%8D%AE%E6%8A%A5%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;UDP协议&lt;/a&gt;，也叫用户数据报协议（User Datagram Protocol）是一个简单的面向数据报的传输层协议。它只管数据包发送，并不没有TCP的连接控制、回复确认，并不知道对方是否接收成功。因为并不等待接收方回复，发送端可以连续发送数据，接收端接收到数据并不一定是顺序的。因此相比TCP，UDP的有更高的传输效率，更低的可靠性。如果需要可靠性，则需要发送确认包，类似TCP那样子。&lt;/p&gt;&#10;&lt;p&gt;通常&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;HTTP协议&lt;/a&gt;基于TCP实现，保证收到的内容是完整、顺序的。在HTTP 1.0时，每一次请求都需要建立TCP连接，关闭TCP连接；在HTTP 1.1时，同一TCP连接则可以在活跃（Keep-Live）间期内复用。HTTP是无连接的，每次处理完成请求即断开连接，一方面可以节省服务器资源，另一方面却浪费连接时间。如果需要维持客户端的Keep-Alive状态，则又需要消耗更多服务器资源，需要权衡。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://zh.wikipedia.org/wiki/WebSocket" target="_blank" rel="noopener"&#10; &gt;WebSocket&lt;/a&gt;是基于TCP 连接上进行全双工通讯的协议，允许服务端直接向浏览器发送消息，不再需要ajax轮询。它也是&lt;a class="link" href="http://stackoverflow.com/questions/35315641/can-tcp-udp-sockets-and-websockets-communicate-with-each-other" target="_blank" rel="noopener"&#10; &gt;在TCP上面的实现&lt;/a&gt;，使用类似HTTP请求的握手协议，进行TCP通信切换。&lt;a class="link" href="https://zh.wikipedia.org/wiki/WebRTC" target="_blank" rel="noopener"&#10; &gt;WebRTC&lt;/a&gt;，也叫Web即时通信（Web Real-Time Communication），则是一个支持浏览器之间进行实时语音对话或视频对话的API。它是建立于TCP/UDP之上的点对点通信，客户端基于上层&lt;a class="link" href="https://www.html5rocks.com/en/tutorials/webrtc/datachannels/" target="_blank" rel="noopener"&#10; &gt;RTCDataChannel&lt;/a&gt;进行通信而非底层TCP/UDP。&lt;/p&gt;&#10;&lt;p&gt;Google推出了基于UDP的&lt;a class="link" href="https://zh.wikipedia.org/wiki/QUIC" target="_blank" rel="noopener"&#10; &gt;QUIC协议（快速UDP网络连接）&lt;/a&gt;实现的HTTP传输，可以快速在两个端点间创建连接，支持多路复用连接。对于丢包问题，则采用冗余传输，能够根据接收到的包，对缺失的包进行恢复（类似RAID）。对于一个TCP连接，需要四个参数：源IP/端口，目的IP/端口，任何一个改变都需要重新建立连接。QUIC则不需要这些，因为UDP并不需要来源信；它使用UUID来标识一个连接，只要这个UUID在，那么这个连接会话就能够继续（与HTTP会话有点像）。因此在不同网络，特别是移动网络之间的切换，都将保持稳定（参考：&lt;a class="link" href="http://Mosh" target="_blank" rel="noopener"&#10; &gt;Mosh&lt;/a&gt;）。目前Google的网站已经支持，并可以在Chrome浏览器的里面查看连接情况：chrome://net-internals/#quic。&lt;/p&gt;&#10;&lt;p&gt;通常说TCP是可靠连接，可用于数据流，复杂网络情况；UDP由于缺少确认机制等，属不可靠连接，通常应用于网络情况良好（内部）或者允许丢包的场景。事实上UDP也应用于游戏，VoIP等需要高效传输的场景。当网络状况糟糕时，使用TCP通信反而可能更差，因为需要更多步骤建立连接和确认。参考这里：&lt;a class="link" href="https://www.zhihu.com/question/20292749" target="_blank" rel="noopener"&#10; &gt;QQ 为什么采用 UDP 协议，而不采用 TCP 协议实现？&lt;/a&gt;。TCP连接是有状态的，服务端需要去维持，及&lt;a class="link" href="http://huoding.com/2013/12/31/316" target="_blank" rel="noopener"&#10; &gt;TIME_WAIT&lt;/a&gt;问题。如果连接一段时间没用，TCP并不能感知连接是否仍然有效，需要自定义心跳包，维持连接。UDP则是无连接状态的，只要知道目标IP及端口即可以发送。&lt;/p&gt;&#10;&lt;p&gt;UDP通信简单许多，不需要socket_connect和socket_connect，主动暴露一端（服务端）需要socket_bind。例如，服务端：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$socket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_server&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;udp://127.0.0.1:1113&amp;#34;&lt;/span&gt;, $errno, $errstr, &lt;span style="color:#a6e22e"&gt;STREAM_SERVER_BIND&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$socket) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$errstr&lt;/span&gt;&lt;span style="color:#e6db74"&gt; (&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$errno&lt;/span&gt;&lt;span style="color:#e6db74"&gt;)&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pkt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_recvfrom&lt;/span&gt;($socket, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, $peer);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$peer&lt;/span&gt;&lt;span style="color:#e6db74"&gt;,&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$pkt&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//客户端互相通信时，注释下面一行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_sendto&lt;/span&gt;($socket, &lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;D M j H:i:s Y&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;), &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, $peer);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($pkt &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sock &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_create&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;AF_INET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOCK_DGRAM&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOL_UDP&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Ping !&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($msg);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;socket_sendto&lt;/span&gt;($sock, $msg, $len, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1113&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//sleep(30)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_recv&lt;/span&gt;( $sock , $reply , &lt;span style="color:#ae81ff"&gt;2045&lt;/span&gt; , &lt;span style="color:#a6e22e"&gt;MSG_WAITALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $reply;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($sock);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;服务端的代码里面有个stream_socket_sendto（或者socket_sendto），向客户端发送消息。UDP并不需要向客户端回复消息，这并像TCP在同一个连接里面回复，而是另一次UDP通信罢了。实际上，两个客户端之间就能够互相通信（分别使用不同端口），任何能够拿到对方IP和端口，都能够向其发送消息。复制客户端代码，更改目标IP和端口为服务端打印出来的信息，然后运行，原先的客户端也将收到消息。利用中间服务器交换两个客户端的IP和端口，以便直接通信，是NAT穿透常用的方法。&lt;/p&gt;&#10;&lt;p&gt;综上，使用TCP可以保证数据可靠传输，复用连接，比如请求-应答模型；使用UDP则可以更高效发送数据，但能容忍部分丢包的场景，比如视频画面；或者只发送不需响应的数据，比如日志；或者无需连接状态的场景（类似HTTP会话），减少服务器压力和客户端等待。当然，也可以在UDP基础上自定义传输规则，实现譬如Mosh或则TCP那样的应用。选择TCP或者UDP，应该综合考虑使用场景，网络，数据包大小，效率，安全等，而不是盲从字面上的“面向可靠的”或者“不可靠的”或者“高效的”。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/tennysonsky/article/details/44562435" target="_blank" rel="noopener"&#10; &gt;如何理解HTTP协议的 “无连接，无状态” 特点？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://ma.ttias.be/googles-quic-protocol-moving-web-tcp-udp/" target="_blank" rel="noopener"&#10; &gt;Google’s QUIC protocol: moving the web from TCP to UDP（&lt;/a&gt;&lt;a class="link" href="http://www.infoq.com/cn/articles/quic-google-protocol-web-platform-from-tcp-to-udp" target="_blank" rel="noopener"&#10; &gt;Google QUIC协议：从TCP到UDP的Web平台&lt;/a&gt;）&lt;br&gt;&#10;&lt;a class="link" href="http://zhihu.com/question/29705994/answer/46357120" target="_blank" rel="noopener"&#10; &gt;如何看待谷歌 Google 打算用 QUIC 协议替代 TCP/UDP？ – 回答作者: Trotyl Yu&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://mosh.org/#techinfo" target="_blank" rel="noopener"&#10; &gt;How Mosh works&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/regedit/articles/829725.html" target="_blank" rel="noopener"&#10; &gt;使用TCP协议的NAT穿透技术&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/php-socket%e9%80%9a%e4%bf%a1/" target="_blank" rel="noopener"&#10; &gt;PHP Socket通信&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/http%e6%96%87%e4%bb%b6%e5%88%86%e5%9d%97%e4%b8%8a%e4%bc%a0%e4%b8%8b%e8%bd%bd/" target="_blank" rel="noopener"&#10; &gt;日志系统设计&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.codingnow.com/2016/03/reliable_udp.html" target="_blank" rel="noopener"&#10; &gt;可靠 UDP 传输&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E9%98%BB%E6%96%B7%E6%9C%8D%E5%8B%99%E6%94%BB%E6%93%8A" target="_blank" rel="noopener"&#10; &gt;DDOS（拒绝服务攻击）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/blognkliming/article/details/17181773" target="_blank" rel="noopener"&#10; &gt;php使用socket感悟–tcp和udp&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.binarytides.com/udp-socket-programming-in-php/" target="_blank" rel="noopener"&#10; &gt;UDP socket programming in php&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/18897917/does-webrtc-use-tcp-or-udp" target="_blank" rel="noopener"&#10; &gt;Does WebRTC use TCP or UDP?&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>日志系统设计</title><link>https://courages.us/%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</link><pubDate>Mon, 03 Oct 2016 22:35:33 +0800</pubDate><guid>https://courages.us/%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</guid><description>&lt;p&gt;日志系统是项目开发/运维当中非常重要的一部分，提供产品使用情况，跟踪调试信息等。以前都是各个项目各自实现日志记录，比如PHP、JAVA各自实现一套，如果要跨项目/服务器进行查询/跟踪/统计，则比较麻烦，比如Web后台–&amp;gt;业务模块–&amp;gt;基础组件，客户端–&amp;gt;公共接口–&amp;gt;业务模块等等。&lt;br&gt;&#10;目前的项目都是将日志写入本地，首先需要定义统一的规范：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;格式&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DateTime | ServerIP | ClientIP | PID | RequestID| Type | Level | Message| Code&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;解释&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DateTime：记录日志的当前时间戳&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ServerIP：当前服务器IP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ClientIP:客户端IP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PID：进程ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RequestID：交易号，即请求的唯一标识，使用uniqid(+UserCode)或UUID或，一次请求会有多条日志，，用于关联本次请求内的相关日志&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type：日志类型，比如统计，操作（审计），业务等&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Level：日志等级&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Message：日志内容，当为值为数组或者对象时转为JSON&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type为RUNTIME时，表示运行日志，属性：自定义&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type为HTTP时，表示来源请求，属性：Url，Method（Get/Post），Params，RemoteIP，UserAgent，ReferUrl[，Action，Method]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type为REST时，表示外部调用，属性：Type（Http/Https），Url,Port，RequestParams，Response，RunTime；&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type为SQL时，表示SQL执行，属性：Sql，RunTime&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Code：标识码，记录错误码、响应码、统计码、版本、自定义信息，方便统计&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的RequestID由入口处自动产生，用于标识一次请求，关联所产生的所有日志，需要在各个项目之间传递。为了减少日志，Level通常为Info级别，避免产生过多日志。为了方便调试追踪，RequestID和Level也可以在其他参数中指明，比如HTTP头里面附加。&lt;br&gt;&#10;然后是日志收集：客户端收走日志系统，发送给日志系统服务端。&lt;br&gt;&#10;然后分析处理呈现：服务端将接收到的日志，发给处理其他组件分析处理，提供Web界面的查询系统。研发人员，可以错误信息，定位问题；获悉程序运行情况进行调优；大数据分析日志，得出产品使用情况；运维平台则可以进行业务报警。&lt;/p&gt;&#10;&lt;p&gt;日志产生由个语言依照规范自行实现，收集、保持则由&lt;a class="link" href="https://flume.apache.org/" target="_blank" rel="noopener"&#10; &gt;Flume&lt;/a&gt;和&lt;a class="link" href="http://kafka.apache.org/" target="_blank" rel="noopener"&#10; &gt;Kafka&lt;/a&gt;实现。Flume是一个分布式的日志收集、合并、移动系统，能够监控文件变化，将变化部分传输出去。Kafka是一个分布式的发布/订阅的消息流平台，包括Broker，Consumer，Producer都支持分布式，依赖&lt;a class="link" href="https://courages.us/php-zookeeper%e5%88%86%e5%b8%83%e5%bc%8f%e6%9c%8d%e5%8a%a1%e5%bc%80%e5%8f%91/" target="_blank" rel="noopener"&#10; &gt;Zookeeper&lt;/a&gt;实现。&lt;/p&gt;&#10;&lt;p&gt;在PHP上面的实现，一开始使用&lt;a class="link" href="https://logging.apache.org/log4php/" target="_blank" rel="noopener"&#10; &gt;log4php&lt;/a&gt;，看起来很美好，但是性能很差，对业务影响较大。决定再次简化，砍掉不必要的东西（Socket，邮件等等），在C语言开发的PHP日志扩展&lt;a class="link" href="https://github.com/Neeke/SeasLog" target="_blank" rel="noopener"&#10; &gt;SeasLog&lt;/a&gt;基础上在做开发，将日志文件保存在本地。为了减少日志所占用内存，每超过一定的大小的日志即进行保存，否则在最后进行保存，利用了Nginx的fastcgi_finish_request特性。生产上发现，每天产生的文件日志太大了，需要控制日志信息大小、等级，并及时清理。&lt;br&gt;&#10;对于Web后台，还结合FirePHP，将日志直接输出到浏览器，方便边运行变调试。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.bitstech.net/2014/01/07/log-best-practice/" target="_blank" rel="noopener"&#10; &gt;最佳日志实践&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://testing.googleblog.com/2013/06/optimal-logging.html" target="_blank" rel="noopener"&#10; &gt;Optimal Logging&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://neoremind.com/2016/05/flumekafka%E6%94%B6%E9%9B%86docker%E5%AE%B9%E5%99%A8%E5%86%85%E5%88%86%E5%B8%83%E5%BC%8F%E6%97%A5%E5%BF%97%E5%BA%94%E7%94%A8%E5%AE%9E%E8%B7%B5/" target="_blank" rel="noopener"&#10; &gt;Flume+Kafka收集Docker容器内分布式日志应用实践&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://tech.meituan.com/mt-log-system-arch.html" target="_blank" rel="noopener"&#10; &gt;基于Flume的美团日志收集系统(一)架构和设计&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/news/2015/09/BookKeeper-Twitter" target="_blank" rel="noopener"&#10; &gt;Twitter是如何构建高性能分布式日志的&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dongxicheng.org/search-engine/log-systems/" target="_blank" rel="noopener"&#10; &gt;开源日志系统比较&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/articles/kafka-analysis-part-1" target="_blank" rel="noopener"&#10; &gt;Kafka剖析（一）：Kafka背景及架构介绍&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://blog.wilddog.com/?p=862" target="_blank" rel="noopener"&#10; &gt;基于Flume的野狗实时日志系统的演进和优化&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/EVODelavega/phpkafka" target="_blank" rel="noopener"&#10; &gt;EVODelavega/phpkafka&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://tech.youzan.com/you-zan-tong-ri-zhi-ping-tai-chu-tan/" target="_blank" rel="noopener"&#10; &gt;有赞统一日志平台初探&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/yangbutao/article/details/8741977" target="_blank" rel="noopener"&#10; &gt;RabbitMQ和kafka从几个角度简单的对比&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000002532284" target="_blank" rel="noopener"&#10; &gt;Flume-ng的原理和使用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dataunion.org/19045.html" target="_blank" rel="noopener"&#10; &gt;利用flume+kafka+storm+mysql构建大数据实时系统&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>HTTP文件分块上传下载</title><link>https://courages.us/http%E6%96%87%E4%BB%B6%E5%88%86%E5%9D%97%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD/</link><pubDate>Sun, 02 Oct 2016 22:16:47 +0800</pubDate><guid>https://courages.us/http%E6%96%87%E4%BB%B6%E5%88%86%E5%9D%97%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD/</guid><description>&lt;p&gt;在开发中经常需要上传下载文件，涉及web页面，手机应用，线下服务器等，文件传输方式有HTTP，FTP，BT。。于是基于HTTP开发了统一文件上传下载接口。&lt;br&gt;&#10;由于上传涉及多端，网络状况复杂，需要能够支持断点续传，因此需要对文件进行分块和校验。&lt;br&gt;&#10;请求上传：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;chunk：当前块编号&lt;/li&gt;&#10;&lt;li&gt;chunks：文件分块总数&lt;/li&gt;&#10;&lt;li&gt;md5：整个文件md5&lt;/li&gt;&#10;&lt;li&gt;content：文件块内容&lt;/li&gt;&#10;&lt;li&gt;size：文件块大小&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;服务端返回:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;statu：状态，0失败，非0成功&lt;/li&gt;&#10;&lt;li&gt;chunk：需要上传的块编号&lt;/li&gt;&#10;&lt;li&gt;message：操作信息&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;服务端有几种情况&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1. 上传成功，md5已经存在，说明文件已存在，则返回上传成功，并结束上传，类似秒传&lt;/li&gt;&#10;&lt;li&gt;2. 上传成功，md5已经不存在，但当前文件块已经存在，说明该文件已经上传过一部分，则返回成功，并给出需要开始上传的块号，类似断点续传&lt;/li&gt;&#10;&lt;li&gt;3. 上传成功，文件块不存在，当前块号小于总块数减一，则返回上传成功，并给出下一块块号&lt;/li&gt;&#10;&lt;li&gt;4. 上传成功，文件块不存在，当前块号等于总块数减一，进行合并，校验成功，则返回上传成功，并结束上传&lt;/li&gt;&#10;&lt;li&gt;5. 上传成功，文件块不存在，当前块号等于总块数减一，进行合并，校验成功，则返回上传失败，从第一块重新开始上传&lt;/li&gt;&#10;&lt;li&gt;6. 上传失败，服务端返回失败，则根据错误信息重传&lt;/li&gt;&#10;&lt;li&gt;7. 上传失败，服务端没有返回，则重传当前块&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;客户端依据自定义的大小对文件进行切割，每次传递一个块，当服务端接收到当前块号为总块数减一则认为全部上传完毕，进行文件块合并，清除临时文件块，计算MD5，如果MD5与传递过来的相等则认为上传成功，否则失败，要求客户端从第一块重传。&lt;br&gt;&#10;这个是基于客户端顺序上传的，假如是并发上传呢？那么就需要在每个分块上传结束后触发合并，需要借助锁来管理。&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/upyun/js-multipart-upload/wiki/%E5%88%86%E5%9D%97%E4%B8%8A%E4%BC%A0%E8%AF%B4%E6%98%8E" target="_blank" rel="noopener"&#10; &gt;又拍云表单分块上传&lt;/a&gt;则分为3步骤：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1.初始化，上报文件信息&lt;/li&gt;&#10;&lt;li&gt;2.上传分块&lt;/li&gt;&#10;&lt;li&gt;3.上传结束，触发合并&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;而&lt;a class="link" href="http://fex.baidu.com/webuploader/" target="_blank" rel="noopener"&#10; &gt;百度的WebUploader&lt;/a&gt;则支持浏览器向服务端的断点续传，利用HTML5或Flash对文件进行分块，计算MD5。&lt;br&gt;&#10;HTTP分块下载，也就是断点续传下载，是根据HTTP1.1协议（RFC2616）中定义的HTTP头 Range和Content-Range字段来控制的：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1. 客户端在HTTP请求头里面指明Range，即开始下载位置&lt;/li&gt;&#10;&lt;li&gt;2. 服务端在HTTP响应头里面返回Content-Range，告知下载其实点和范围&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;服务端可以将文件MD5等加入Etag或自定义Header字段里面，HTTP客户端便可以分开请求数据，最后合并；否则永远都是从头开始。其实也可以把大文件切成多个小文件，再一个个下载回来合并。&lt;br&gt;&#10;有些web服务器直接支持文件上传和下载的断点续传，比如Nginx。&lt;/p&gt;&#10;&lt;p&gt;刚才的文件分块传输过程，有点像TCP通信，也有建立连接，分片，校验，重发，断开连接。&lt;br&gt;&#10;而这个将大任务分解为多个小任务进行处理的思想，即准备–&amp;gt;循环（并行）处理–&amp;gt;结束，可以应用到很多项目里面，比如大数据，爬虫。为Web管理系统写了jQuery插件用来处理的耗时任务，将一个耗时任务分解为多个循环请求，避免超时&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1. prepare：服务端返任务标示ID，总步骤，及附加参数&lt;/li&gt;&#10;&lt;li&gt;2. process：根据返回参数进行循环请求&lt;/li&gt;&#10;&lt;li&gt;3. complete:循环完成，触发结束&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;后面又延伸出另外一个插件，支持任意顺序步骤的处理。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/kazaff/me.kazaff.article/blob/master/%E8%81%8A%E8%81%8A%E5%A4%A7%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0.md" target="_blank" rel="noopener"&#10; &gt;聊聊大文件上传&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/blueimp/JavaScript-MD5" target="_blank" rel="noopener"&#10; &gt;md5 javascript&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/xifeijian/article/details/8712439" target="_blank" rel="noopener"&#10; &gt;HTTP协议－－断点续传&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.chinaunix.net/uid-25267728-id-4095080.html" target="_blank" rel="noopener"&#10; &gt;http断点续传的秘密&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.linuxprobe.com/nginx-upload-module.html" target="_blank" rel="noopener"&#10; &gt;nginx-upload-module模块实现文件断点续传&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/jony413/articles/4906854.html" target="_blank" rel="noopener"&#10; &gt;通过curl测试服务器是否支持断点续传&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>分布式系统</title><link>https://courages.us/%E5%AD%A6%E4%B9%A0%E5%BF%83%E5%BE%97/</link><pubDate>Sat, 16 Apr 2016 10:50:33 +0800</pubDate><guid>https://courages.us/%E5%AD%A6%E4%B9%A0%E5%BF%83%E5%BE%97/</guid><description>&lt;p&gt;好久以前写的了。在InfoQ上学习了&lt;a class="link" href="http://www.infoq.com/cn/presentations/design-and-implementation-of-distributed-monitoring-system" target="_blank" rel="noopener"&#10; &gt;分布式监控系统的设计与实现&lt;/a&gt;、&lt;a class="link" href="http://www.infoq.com/cn/presentations/technology-of-weixin-moments" target="_blank" rel="noopener"&#10; &gt;微信朋友圈技术之道&lt;/a&gt;，在架构设计的基础思想并不复杂。&lt;br&gt;&#10;首先是微信朋友圈技术之道，介绍了微信朋友圈团队的开发，团队仅４个人，因为他们站在巨人的肩膀上：&lt;br&gt;&#10;基础环境&lt;br&gt;&#10;全部才用C＋＋开发&lt;br&gt;&#10;混合部署普通服务器&lt;br&gt;&#10;海量带宽&lt;/p&gt;&#10;&lt;p&gt;强大的基础设施&lt;br&gt;&#10;腾讯CDN，图片和视频上传、存储、分发&lt;br&gt;&#10;RPC框架&lt;br&gt;&#10;Key－Value（KV）存储系统&lt;br&gt;&#10;强大、方便、灵活的部署系统&lt;br&gt;&#10;强大的RPC框架&lt;br&gt;&#10;C＋＋的框架&lt;br&gt;&#10;支持protobuf描述接口&lt;br&gt;&#10;支持进程/线程/协程多种模式：支持数十万的并发协程，方便编写和调试“同步”的网络调用和服务&lt;br&gt;&#10;从CGI到叶子服务器，全系统透明支持过载保护和QOS&lt;br&gt;&#10;为每次CGI调用自动生成全系统调用关系图&lt;br&gt;&#10;每个服务自动内建500多个监控项&lt;br&gt;&#10;高性能Key-value存储系统&lt;br&gt;&#10;三机一组，三机间支持数据一致性，容忍一台机器出错、自动切换&lt;br&gt;&#10;三机分布在一个数据中心的三个独立园区，在任意一个园区提供本区读写服务，容忍一个园区网络隔离&lt;/p&gt;&#10;&lt;p&gt;微信架构&lt;br&gt;&#10;接入层，维持长连接，避免重复连接开销；推送消息&lt;br&gt;&#10;逻辑层，注册/登录，消息，朋友圈，LBS；批处理，群聊，通知，好友推荐&lt;br&gt;&#10;存储代理层，账号，消息，关系链，朋友圈，群管理&lt;br&gt;&#10;存储层，Key-value存储&lt;br&gt;&#10;性能水平扩展（sharding）&lt;br&gt;&#10;相册，按照用户做水平扩展&lt;br&gt;&#10;发表，按照发表key做水平扩展&lt;br&gt;&#10;评论，按照评论key做水平扩展&lt;br&gt;&#10;时间线，按照用户做水平扩展&lt;/p&gt;&#10;&lt;p&gt;发表流程&lt;br&gt;&#10;上传图片到CDN，查找最近节点&lt;br&gt;&#10;调用朋友圈CGI&lt;br&gt;&#10;添加新发表&lt;br&gt;&#10;在相册增加新发表索引&lt;br&gt;&#10;添加时间线更新任务，批处理，给好友时间线添加新索引&lt;br&gt;&#10;返回发表成功&lt;/p&gt;&#10;&lt;p&gt;浏览流程&lt;br&gt;&#10;调用朋友圈CGI&lt;br&gt;&#10;拉取时间线&lt;br&gt;&#10;拉取新发表元数据&lt;br&gt;&#10;拉取CDN上的图片&lt;/p&gt;&#10;&lt;p&gt;数据单副本、索引写扩散、检查更新单读取&lt;br&gt;&#10;数据（发表）单副本：减少内存开销&lt;br&gt;&#10;索引写扩散、检查更新单读取：减少检查更新时的读扩散&lt;br&gt;&#10;写比较慢，失败可以重试；读不可等待&lt;/p&gt;&#10;&lt;p&gt;赞、评论与浏览&lt;br&gt;&#10;往赞、评论表插入发表索引和对应赞、评论&lt;/p&gt;&#10;&lt;p&gt;微信部署、接入与容灾&lt;br&gt;&#10;1地3园区对等部署，对等接入（电信、移动、联通）；数据对等分布于同步；对等服务&lt;br&gt;&#10;容灾，任何两个园区都可以提供全量无损服务&lt;br&gt;&#10;数据中心分布：上海、深圳、香港、加拿大&lt;br&gt;&#10;通信优先专线服务；其次公网（加密）&lt;br&gt;&#10;各数据中心可独立提供服务&lt;br&gt;&#10;各数据中心通过idc queue异步同步写入（自动重试）&lt;/p&gt;&#10;&lt;p&gt;核心数据读写分析&lt;br&gt;&#10;相册与发表&lt;br&gt;&#10;本地idc写入，单向同步到其他idc&lt;br&gt;&#10;key的全局唯一性保证无冲突（根据idc预先生成）&lt;br&gt;&#10;时间线&lt;br&gt;&#10;本地idc只保存本地用户时间线的key，无需同步&lt;/p&gt;&#10;&lt;p&gt;跨洋同步的挑战和应对&lt;br&gt;&#10;挑战：大带宽延迟、丢包、乱序、低可靠性（专心中断）&lt;br&gt;&#10;应对：延迟、丢包、乱序达到一定程度自动从tcp切换到udp；专线中断自动切换到公网（AES加密）&lt;/p&gt;&#10;&lt;p&gt;评论、赞写冲突&lt;br&gt;&#10;因果一致性（不同数据中心保证key不重复，比如不同idc取模）&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/presentations/design-and-implementation-of-distributed-monitoring-system" target="_blank" rel="noopener"&#10; &gt;分布式监控系统的设计与实现&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/presentations/technology-of-weixin-moments" target="_blank" rel="noopener"&#10; &gt;微信朋友圈技术之道&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>MySql 慢日志分析</title><link>https://courages.us/mysql-%E6%85%A2%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90/</link><pubDate>Mon, 05 Oct 2015 14:27:50 +0800</pubDate><guid>https://courages.us/mysql-%E6%85%A2%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90/</guid><description>&lt;p&gt;最近老是碰上MySql报错：1203:User already has more than ‘max_user_connections’ active，之前都没出现过，感觉应该是慢查询导致的。向运维拷贝慢日志分析，慢日志开、启配置参考&lt;a class="link" href="http://my.oschina.net/moooofly/blog/160201" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;br&gt;&#10;拷贝出来的日志很大，需要按故障时间点做一下切割，以便缩小排查范围。按照&lt;a class="link" href="https://github.com/wubx/mysql-binlog-statistic/blob/master/bin/cutlogbytime" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;提供的cutlogbytime.pl脚本运行却报错&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./cutlogbytime.pl slow.log &lt;span style="color:#ae81ff"&gt;1443103200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1443117600&lt;/span&gt; &amp;gt; yestoday.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 1:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 4:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./cutlogbytime.pl: line 5: use: command not found&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 5:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./cutlogbytime.pl: line 6: use: command not found&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 6:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 7:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/cutlogbytime.pl: line 8: syntax error near unexpected token `{&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;/cutlogbytime.pl: line 8: &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;@ARGV&amp;lt;2&lt;span style="color:#f92672"&gt;){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;去掉顶行的空格后再运行，还是报错&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./cutlogbytime.pl slow.log &lt;span style="color:#ae81ff"&gt;1443103200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1443117600&lt;/span&gt; &amp;gt; today.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-bash: ./cutlogbytime.pl: /usr/bin/perl^M: bad interpreter: No such file or directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后参考&lt;a class="link" href="http://stackoverflow.com/questions/2517106/why-do-i-get-use-command-not-found-when-i-run-my-perl-script" target="_blank" rel="noopener"&#10; &gt;stackoverflow上面的答案&lt;/a&gt;更改运行方式为Perl（而不是shell），就可以了。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl cutlogbytime.pl slow.log &lt;span style="color:#ae81ff"&gt;1443103200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1443117600&lt;/span&gt; &amp;gt; today.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;利用mysqlslowdump（perl脚本）来分析日志，-s参数表示排序方式：r表示影响行数（Rows），t表示耗时（Time），c表示查询次数（Count）&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@entos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl mysqldumpslow.pl -s r -t &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; today4.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Reading mysql slow query log from today4.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; Time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;190.48s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;190s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Lock&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0.00s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Rows&lt;span style="color:#f92672"&gt;=&lt;/span&gt;21829854.0 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;21829854&lt;span style="color:#f92672"&gt;)&lt;/span&gt;, xx&lt;span style="color:#f92672"&gt;[&lt;/span&gt;xxxx&lt;span style="color:#f92672"&gt;]&lt;/span&gt;@&lt;span style="color:#f92672"&gt;[&lt;/span&gt;192.168.10.139&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SELECT /*!N SQL_NO_CACHE */ * FROM &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;errormessage&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count: &lt;span style="color:#ae81ff"&gt;32791&lt;/span&gt; Time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;40.95s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1342865s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Lock&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0.05s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1512s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Rows&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1.0 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;32791&lt;span style="color:#f92672"&gt;)&lt;/span&gt;, xx&lt;span style="color:#f92672"&gt;[&lt;/span&gt;xxxx&lt;span style="color:#f92672"&gt;]&lt;/span&gt;@10hosts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; * from connectinfo where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N ORDER BY CreateDatetime DESC LIMIT N&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; Time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;3.71s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;11s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Lock&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0.02s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Rows&lt;span style="color:#f92672"&gt;=&lt;/span&gt;300.0 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;900&lt;span style="color:#f92672"&gt;)&lt;/span&gt;, xx&lt;span style="color:#f92672"&gt;[&lt;/span&gt;xxxx&lt;span style="color:#f92672"&gt;]&lt;/span&gt;@2hosts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; SeverName from errormessage where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt; and ServerType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N and level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N and MsgType &amp;lt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; N&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个语句返回行数21829854，查看具体慢日志，之后需要插入这张表的进程均处于等待状态。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Time: 150924 1:03:12&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# User@Host: xx[xxxx] @ [192.168.10.139] Id: 1493761&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Query_time: 190.479062 Lock_time: 0.000000 Rows_sent: 21829854 Rows_examined: 21829854&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp=1443027792;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SELECT /*!40001 SQL_NO_CACHE */ * FROM `errormessage`;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Time: 150924 1:03:14&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# User@Host: xx[xxxx] @ [192.168.10.168] Id: 1498010&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Query_time: 59.669817 Lock_time: 57.159403 Rows_sent: 0 Rows_examined: 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp=1443027794;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;insert into errormessage (`ID`,`ServerType`,`MsgType`,`Level`,`dev`,`content`,`EventTime`,`SeverName`) values ( &amp;#39;1217&amp;#39;, &amp;#39;3&amp;#39;, &amp;#39;4&amp;#39;, &amp;#39;4&amp;#39;, &amp;#39;827&amp;#39;, &amp;#39;erc:start erc error,songid=46243,keymd5=ee1275b26762e85a7f00e9890bdc092e,ercmd5=abbc3ea9102dbd003b7aa0547dcbf6fa&amp;#39;, &amp;#39;2015-09-23 21:49:27&amp;#39;, &amp;#39;192.168.15.117&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# User@Host: xx[xxxx] @ [192.168.10.205] Id: 1494756&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Query_time: 157.211158 Lock_time: 154.673647 Rows_sent: 0 Rows_examined: 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp=1443027794;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;insert into errormessage (`ID`,`ServerType`,`MsgType`,`Level`,`dev`,`content`,`EventTime`,`SeverName`) values ( &amp;#39;865&amp;#39;, &amp;#39;3&amp;#39;, &amp;#39;1&amp;#39;, &amp;#39;2&amp;#39;, &amp;#39;106&amp;#39;, &amp;#39;检测正常！&amp;#39;, &amp;#39;2015-09-24 01:01:18&amp;#39;, &amp;#39;192.168.0.33&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# User@Host: xx[xxxx] @ [192.168.10.213] Id: 1496479&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Query_time: 100.733230 Lock_time: 98.210902 Rows_sent: 0 Rows_examined: 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp=1443027794;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;insert into errormessage (`ID`,`ServerType`,`MsgType`,`Level`,`dev`,`content`,`EventTime`,`SeverName`) values ( &amp;#39;2472&amp;#39;, &amp;#39;3&amp;#39;, &amp;#39;2&amp;#39;, &amp;#39;4&amp;#39;, &amp;#39;809&amp;#39;, &amp;#39;videoseripnoconfig&amp;#39;, &amp;#39;2015-09-24 01:02:26&amp;#39;, &amp;#39;192.168.0.18&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分析这几天的日志，发现故障时间点附近都是这个语句引起后面的SQL堵塞。原来是每天早上1点开始备份并同步全表数据，锁住了这个表导致后面的所有这个表的insert操作处于等待状态。mysqldump应该使用&lt;a class="link" href="http://dba.stackexchange.com/questions/71961/mysqldump-single-transaction-yet-update-queries-are-waiting-for-the-backup" target="_blank" rel="noopener"&#10; &gt;–single-transaction来避免锁表&lt;/a&gt;，类似下面&lt;a class="link" href="http://tencentdba.com/blog/mysqldump-backup-principle/" target="_blank" rel="noopener"&#10; &gt;这个&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysqldump –uuser -p --skip-opt -q -R --single-transaction --default-character-set&lt;span style="color:#f92672"&gt;=&lt;/span&gt;utf8 --master-data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; --create-option --no-autocommit –S &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;sock&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; -B &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DBName&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; &amp;gt; backup.sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是这样仍然是全表扫描进行备份，如果能够增量备份的话，影响要小很多，或者数据做冷热/新旧之分，定期将新（每天）/热数据转入旧（历史）/冷数据中。后面运维的解决方案是：升级数据库机器从虚拟机变为实体机，配置从机，并从从机进行备份同步。&lt;/p&gt;&#10;&lt;p&gt;上面mysqlslowdump使用影响行数来排序，事实上用另外两个类型（时间，次数）分析结果是connectinfo比较频繁，一直以来都认为是这个表的操作引起的。这里还尝试了其他工具来分析，使用&lt;a class="link" href="https://github.com/daniel-nichter/hackmysql.com/tree/master/mysqlsla" target="_blank" rel="noopener"&#10; &gt;mysqlsla.pl&lt;/a&gt;进行分析，相关参数选项参考&lt;a class="link" href="https://code.google.com/p/memcache-top/issues/detail?id=12" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl mysqlsla.pl today.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Auto-detected logs as slow logs&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Report &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; slow logs: today4.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;60.57k queries total, &lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; unique&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sorted by &lt;span style="color:#e6db74"&gt;&amp;#39;t_sum&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Grand Totals: Time 5.38M s, Lock 3.22M s, Rows sent 21.86M, Rows Examined 184.46M&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;______________________________________________________________________ &lt;span style="color:#ae81ff"&gt;001&lt;/span&gt; ___&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count : 25.59k &lt;span style="color:#f92672"&gt;(&lt;/span&gt;42.24%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time : 3905525.574451 s total, 152.643069 s avg, 113.07488 s to 2720.338946 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;72.64%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Time : 3260112.482495 s total, 134.12789 s avg, 113.07488 s to 282.366041 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Lock Time &lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; : 3168076.975558 s total, 123.820721 s avg, 108.548105 s to 311.639359 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;98.45%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Lock : 2961933.212121 s total, 121.860167 s avg, 108.548105 s to 123.487106 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows sent : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; to &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.00%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows examined : &lt;span style="color:#ae81ff"&gt;54&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; to 4.92k max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.75%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Users :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.147 : 10.65% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2724&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.26% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6215&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.209 : 10.33% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2643&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6156&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.205 : 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2599&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.97% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6036&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.211 : 10.13% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2591&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.98% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6042&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.207 : 9.93% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2541&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6024&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.161 : 9.83% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2515&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.84% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5960&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.149 : 9.81% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2510&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6028&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.215 : 9.76% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2498&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.85% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5963&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.168 : 9.71% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2485&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.69% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5868&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.213 : 9.69% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2480&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.66% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5851&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query abstract:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N; UPDATE connectinfo SET devicetag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, connectipaddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, updatedatetime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;now&lt;span style="color:#f92672"&gt;()&lt;/span&gt; WHERE ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N AND apptype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query sample:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1443027797;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;update connectinfo set DeviceTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;1070A416AF000000&amp;#39;&lt;/span&gt;, ConnectIPAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;60.174.116.165&amp;#39;&lt;/span&gt;, UpdateDatetime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;now&lt;span style="color:#f92672"&gt;()&lt;/span&gt; where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5358&lt;/span&gt; and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;______________________________________________________________________ &lt;span style="color:#ae81ff"&gt;002&lt;/span&gt; ___&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count : 32.79k &lt;span style="color:#f92672"&gt;(&lt;/span&gt;54.14%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time : 1344378.871914 s total, 40.99841 s avg, 2.000747 s to 1944.548192 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;25.01%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Time : 587407.556704 s total, 18.85678 s avg, 2.000747 s to 233.465042 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Lock Time &lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; : 1512.917798 s total, 46.138 ms avg, &lt;span style="color:#ae81ff"&gt;76&lt;/span&gt; ▒s to 114.302 ms max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.05%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Lock : 1414.978902 s total, 45.423 ms avg, &lt;span style="color:#ae81ff"&gt;76&lt;/span&gt; ▒s to 50.514 ms max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows sent : &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; to &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.15%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows examined : 4.92k avg, 4.92k to 4.92k max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;87.41%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Users :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.209 : 10.24% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3359&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6156&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.149 : 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3331&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6028&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.147 : 10.11% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3315&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.26% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6215&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.211 : 10.03% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3288&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.98% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6042&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.207 : 10.02% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3285&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6024&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.161 : 9.97% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3268&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.84% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5960&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.215 : 9.96% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3266&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.85% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5963&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.205 : 9.92% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3254&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.97% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6036&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.168 : 9.86% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3234&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.69% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5868&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.213 : 9.73% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3191&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.66% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5851&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query abstract:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N; SELECT * FROM connectinfo WHERE ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N AND apptype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N ORDER BY createdatetime DESC LIMIT N;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query sample:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1443027795;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; * from connectinfo where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7646&lt;/span&gt; and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ORDER BY CreateDatetime DESC LIMIT 1;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;______________________________________________________________________ &lt;span style="color:#ae81ff"&gt;003&lt;/span&gt; ___&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count : &lt;span style="color:#ae81ff"&gt;842&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.39%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time : 66663.314786 s total, 79.172583 s avg, 2.011408 s to 673.604537 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.24%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Time : 56684.989954 s total, 70.944919 s avg, 2.011408 s to 193.623235 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Lock Time &lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; : 48221.988255 s total, 57.27077 s avg, &lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; ▒s to 185.402303 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.50%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Lock : 40627.196184 s total, 50.847555 s avg, &lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; ▒s to 166.67704 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows sent : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; to &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.00%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows examined : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; to &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.00%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Users :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.207 : 11.64% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;98&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6024&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.205 : 11.28% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;95&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.97% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6036&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.213 : 10.93% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;92&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.66% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5851&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.161 : 10.45% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;88&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.84% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5960&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.149 : 10.33% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;87&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6028&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.211 : 9.74% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;82&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.98% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6042&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.147 : 9.38% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.26% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6215&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.215 : 9.38% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.85% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5963&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.168 : 9.03% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;76&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.69% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5868&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.209 : 7.84% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;66&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6156&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query abstract:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N; INSERT INTO errormessage &lt;span style="color:#f92672"&gt;(&lt;/span&gt;id,servertype,msgtype,level,dev,content,eventtime,severname&lt;span style="color:#f92672"&gt;)&lt;/span&gt; VALUES &lt;span style="color:#f92672"&gt;(&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;1;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用mysqlsla可以看SQL语句的执行数量/比例，影响行数，用户，占比等。，从这里看很可能认为是connectinfo表（95%以上）引起，SHOW PROCESSLIST也是如此 。&lt;br&gt;&#10;由于这个文件我是单独下载回来的，运行mysqlsla.pl时候碰到很多错误，逐个安装解决了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl mysqlsla.pl today.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Can&lt;span style="color:#e6db74"&gt;&amp;#39;t locate Time/HiRes.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at mysqlsla.pl line 2092.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;BEGIN failed--compilation aborted at mysqlsla.pl line 2092.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;#解决方法&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[vagrant@centos64 mysql-log-filter-1.9]$ sudo yum install perl-Time-HiRes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[vagrant@centos64 mysql-log-filter-1.9]$ perl -MCPAN -e &amp;#39;&lt;/span&gt;install DBI&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Can&amp;#39;&lt;/span&gt;t locate CPAN.pm in @INC &lt;span style="color:#f92672"&gt;(&lt;/span&gt;@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BEGIN failed--compilation aborted.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#解决方法&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ sudo yum install perl-DBI&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;正确的方法是应该检测对应根目录下面的Makefile.PL，比如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 percona-toolkit-2.2.15&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl Makefile.PL&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#如果报以下错误，需要先安装对应模块，简单点就是&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#sudo yum install perl-devel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Can&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;t locate ExtUtils/MakeMaker.pm in @INC &lt;span style="color:#f92672"&gt;(&lt;/span&gt;@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .&lt;span style="color:#f92672"&gt;)&lt;/span&gt; at Makefile.PL line 1.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BEGIN failed--compilation aborted at Makefile.PL line 1.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后安装对应模块，参考&lt;a class="link" href="http://modperlbook.org/html/3-9-1-Installing-Perl-Modules-into-a-Nonstandard-Directory.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;br&gt;&#10;使用Percona公司的工具&lt;a class="link" href="https://www.percona.com/doc/percona-toolkit/2.2/pt-query-digest.html" target="_blank" rel="noopener"&#10; &gt;pt-query-diges&lt;/a&gt;t来分析也得到了同mysqlsla类似的结果&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pt-query-digest ../../today4.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 9.8s user time, 700ms system time, 21.05M rss, 73.66M vsz&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Current date: Mon Oct 5 05:52:01 2015&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Hostname: vagrant-centos64.vagrantup.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Files: ../../today.log&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Overall: 60.57k total, 17 unique, 4.54 QPS, 402.68x concurrency ________&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Time range: 2015-09-23 22:17:29 to 2015-09-24 02:00:00&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Attribute total min max avg 95% stddev median&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ============ ======= ======= ======= ======= ======= ======= =======&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Exec time 5376198s 2s 2720s 89s 258s 118s 57s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Lock time 3217840s 0 312s 53s 118s 60s 48ms&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rows sent 20.85M 0 20.82M 361.00 0.99 84.46k 0.99&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rows examine 175.91M 0 20.82M 2.97k 4.71k 84.48k 4.71k&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Query size 7.85M 64 597 135.90 151.03 27.56 112.70&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Profile&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rank Query ID Response time Calls R/Call V/M Item&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ==== ================== ================== ===== ======== ===== ========&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1 0xF1132168DB0BFC57 3905525.5745 72.6% 25586 152.6431 61.61 UPDATE connectinfo&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 2 0xD4B317E755A0ABD7 1344378.8719 25.0% 32791 40.9984 30... SELECT connectinfo&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 3 0xE23849EE6FB19DAE 66663.3148 1.2% 842 79.1726 62.99 INSERT errormessage&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Query 1: 7.52 QPS, 1.15kx concurrency, ID 0xF1132168DB0BFC57 at byte 16243195&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# This item is included in the report because it matches --limit.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Scores: V/M = 61.61&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Time range: 2015-09-24 01:03:17 to 02:00:00&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Attribute pct total min max avg 95% stddev median&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ============ === ======= ======= ======= ======= ======= ======= =======&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Count 42 25586&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Exec time 72 3905526s 113s 2720s 153s 271s 97s 124s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Lock time 98 3168077s 109s 312s 124s 118s 14s 118s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rows sent 0 0 0 0 0 0 0 0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rows examine 0 1.33M 0 4.80k 54.39 0 504.65 0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Query size 48 3.78M 149 157 154.94 151.03 0.52 151.03&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# String:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Hosts 192.168.10.147 (2724/10%)... 9 more&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Users gate&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Query_time distribution&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1us&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 10us&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 100us&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1ms&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 10ms&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 100ms&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 10s+ ################################################################&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Tables&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# SHOW TABLE STATUS LIKE &amp;#39;connectinfo&amp;#39;\G&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# SHOW CREATE TABLE `connectinfo`\G&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;update connectinfo set DeviceTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;10705BDDCD000000&amp;#39;&lt;/span&gt;, ConnectIPAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;115.231.63.78&amp;#39;&lt;/span&gt;, UpdateDatetime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;now&lt;span style="color:#f92672"&gt;()&lt;/span&gt; where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6912&lt;/span&gt; and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0&lt;span style="color:#ae81ff"&gt;\G&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Converted for EXPLAIN&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# EXPLAIN /*!50100 PARTITIONS*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; DeviceTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;10705BDDCD000000&amp;#39;&lt;/span&gt;, ConnectIPAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;115.231.63.78&amp;#39;&lt;/span&gt;, UpdateDatetime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;now&lt;span style="color:#f92672"&gt;()&lt;/span&gt; from connectinfo where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6912&lt;/span&gt; and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0&lt;span style="color:#ae81ff"&gt;\G&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PS：这个问题解决后没几天，数据库又出问题，以为又是慢SQL什么的，结果是交换机网口问题。。。数据传输太慢，导致主从不同步。。。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://hzcsky.blog.51cto.com/1560073/479991" target="_blank" rel="noopener"&#10; &gt;mysql 慢日志分析&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://bbs.chinaunix.net/thread-4076473-1-1.html" target="_blank" rel="noopener"&#10; &gt;慢日志按时间截取&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://my.oschina.net/moooofly/blog/160201" target="_blank" rel="noopener"&#10; &gt;MySQL 之 slow log&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/zhanjindong/p/3472804.html" target="_blank" rel="noopener"&#10; &gt;MySQL优化—工欲善其事，必先利其器（2）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.wllog.net/2014/09/02/744.html" target="_blank" rel="noopener"&#10; &gt;日志常用统计技巧&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://sunheran.com/2015/03/12/mysql-sql-performance/" target="_blank" rel="noopener"&#10; &gt;性能优化之MySQL优化（一）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/wyzxg/article/details/7268969" target="_blank" rel="noopener"&#10; &gt;mysqlsla的安装与使用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://cocos.iteye.com/blog/1122836" target="_blank" rel="noopener"&#10; &gt;安装DBI组件。 Can’t locate DBI.pm in @INC-mysql接口&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://code.google.com/p/memcache-top/issues/detail?id=12" target="_blank" rel="noopener"&#10; &gt;Issue 12: Can’t locate Time/HiRes.pm&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ccvita.com/326.html" target="_blank" rel="noopener"&#10; &gt;打开MySQL的慢查询记录&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://perl%20Makefile.PL" target="_blank" rel="noopener"&#10; &gt;“Can’t locate ExtUtils/MakeMaker.pm” while compile git&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.olindata.com/blog/2014/08/analysing-slow-mysql-queries-pt-query-digest" target="_blank" rel="noopener"&#10; &gt;analysing slow MySQL queries with pt-query-digest&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://tencentdba.com/blog/mysqldump-backup-principle/" target="_blank" rel="noopener"&#10; &gt;mysqldump备份原理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dba.stackexchange.com/questions/71961/mysqldump-single-transaction-yet-update-queries-are-waiting-for-the-backup" target="_blank" rel="noopener"&#10; &gt;mysqldump –single-transaction, yet update queries are waiting for the backup&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.51yip.com/mysql/1042.html" target="_blank" rel="noopener"&#10; &gt;mysql 利用binlog增量备份，还原实例&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://bbs.chinaunix.net/thread-1017116-1-1.html" target="_blank" rel="noopener"&#10; &gt;MySQl备份恢复策略（完全+增量备份策略）&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Git及GitHub 使用</title><link>https://courages.us/git%E5%8F%8Agithub-%E4%BD%BF%E7%94%A8/</link><pubDate>Sun, 30 Aug 2015 16:46:59 +0800</pubDate><guid>https://courages.us/git%E5%8F%8Agithub-%E4%BD%BF%E7%94%A8/</guid><description>&lt;p&gt;在前面的文章里面，经常会看到使用&lt;a class="link" href="https://git-scm.com/" target="_blank" rel="noopener"&#10; &gt;Git&lt;/a&gt;来下载代码，比如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git clone https://github.com/zeromq/zeromq4-x.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Git 是有Linux开发者Linus Torvalds开发的分布式版本控制软件，最初用于Linux内核代码管理，它不需要服务器端软件，就可以进行版本控制，使得离线/本地开发非常方便。与SVN不同，Git基本在本机工作（就像在本机也搭建了一个SVN服务器），具有以下优点：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;可以向本地提交代码，当服务器不可用时，仍然可以离线提交代码&lt;/li&gt;&#10;&lt;li&gt;可以向本地提交代码，在本地功能开发完成后，再向服务器提交有用的变更，项目代码不会有频繁变更&lt;/li&gt;&#10;&lt;li&gt;分布式存储，每个开发者均有一份代码，不用担心服务器上的代码丢失&lt;/li&gt;&#10;&lt;li&gt;支持Pull Request，功能完成后通知其他成员进行代码审查&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Git提倡使用主干作为稳定可发布的代码，使用分支进行开发，与我们的软件管理思路大致一致：分支开发，分支测试，分支/主干发布。多人协作项目，需要有良好的分支开发意识，以免在主干上互相冲突和影响软件稳定。&lt;br&gt;&#10;通过MINGW32安装&lt;a class="link" href="https://git-scm.com/download/win" target="_blank" rel="noopener"&#10; &gt;Git&lt;/a&gt;，在Windows下面也可以使用Git。它提供了在右键菜单里面集成了Git管理的一些操作，也提供了Bash进行交互。Git常用操作包括：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 获取帮助&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git --help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 获取某个git命令的帮助信息，使用默认浏览器查看&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git help branch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 初始化当前目录作为git仓库&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git init&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 复制一个远程仓库到本地&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git clone &amp;lt;url&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 切换到主分支master（默认）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git checkout master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 设置个人账号信息，提交代码时会同时提交这些信息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git config --global user.name &lt;span style="color:#e6db74"&gt;&amp;#34;mystery&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git config --global user.email mystery@example.com:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 提交全部代码变更&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git add --all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 仅提交boot.php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git add boot.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 仅提交路径generator/lib&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git add generator/lib&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 仅提交路径generator/lib&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git add generator/lib&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 删除文件 test.php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git rm test.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 移动文件 test.php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git mvtest.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看当前代码是否有未提交的变更&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 比较代码差异&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git diff&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 确认提交代码并备注&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git commit -m &lt;span style="color:#e6db74"&gt;&amp;#39;test comment &amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 自动提交所有文件变更，不需要上面的步骤了&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git commit -a -m &lt;span style="color:#e6db74"&gt;&amp;#39;added new comments&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看提交历史记录&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看历史记录前2条，并显示变更&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git log -p -2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 撤销上一次commit修改&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git reset HEAD&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 与远程仓库库同步&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git fetch origin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git rebase origin/master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 多个本地合并commit合并成一个&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git rebase -i origin/master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 推送本地更新到远程仓库&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git push --force origin feature-x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在master分支上创建分支develop，-b则表示创建分支并切换到该分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git checkout -b develop master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在develop分支上创建feature-x分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git checkout -b feature-x develop&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 列出所有分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git branch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 创建master分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git branch master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 删除分支feature-x&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git branch -d feature-x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在mater上面合并feature-x分支代码&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git checkout master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git merge feature-x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 合并远程仓库代码到本地&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git pull origin master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git fetch origin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git merge --no-ff origin/master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看当前镜像&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git tag&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 为当前仓库创建一个镜像标签&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git tag -a v1.0 -m &lt;span style="color:#e6db74"&gt;&amp;#39;publish &amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在已有项目目录上使用git&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git init .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git remote add origin &amp;lt;repository-url&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git pull origin master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git add .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git commit -am &lt;span style="color:#e6db74"&gt;&amp;#34;commit message&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push　origin master&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Git还提供了一个工具，可以将svn仓库代码导入git仓库，参考&lt;a class="link" href="http://gitbook.liuhui998.com/6_4.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://github.com/" target="_blank" rel="noopener"&#10; &gt;GitHub&lt;/a&gt;是一个著名的在线代码托管/分享/交流网站，提供免费的代码托管服务，支持分布式版本控制软件Git管理的工程代码，方便交流和协作。在这里可以找到各种各样的开源软件代码，比如&lt;a class="link" href="https://github.com/php/php-src" target="_blank" rel="noopener"&#10; &gt;PHP-SRC&lt;/a&gt;，对于程序员的帮助也是显而易见的，反之从一个程序员关注的项目也可以看出一个人的开发方向和水平。&lt;/p&gt;&#10;&lt;p&gt;GitHub开发了一个&lt;a class="link" href="https://desktop.github.com/" target="_blank" rel="noopener"&#10; &gt;客户端&lt;/a&gt;用于与GitHub网站进行交互，隐藏了一些操作的细节，相比SVN要大气，方便一些。但是在线安装的方式对于国内并不方面。。&lt;br&gt;&#10;通过GitHub客户端可以直接创建、管理GitHub线上托管的代码。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/08/git-1.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="git-1" class="gallery-image" data-flex-basis="416px" data-flex-grow="173" height="173" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/08/git-1-300x173.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/08/git-2.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="git-2" class="gallery-image" data-flex-basis="375px" data-flex-grow="156" height="192" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/08/git-2-300x192.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;与TortoiseSVN类似，也有&lt;a class="link" href="https://github.com/TortoiseGit/TortoiseGit" target="_blank" rel="noopener"&#10; &gt;TortoiseGit&lt;/a&gt;用于Windows下面的Git管理。&lt;br&gt;&#10;作公司内部的代码管理，可以使用&lt;a class="link" href="https://about.gitlab.com/" target="_blank" rel="noopener"&#10; &gt;GitLab&lt;/a&gt;来搭建私有的代码托管服务器，参考&lt;a class="link" href="https://phphub.org/topics/576" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.ruanyifeng.com/blog/2015/08/git-use-process.html" target="_blank" rel="noopener"&#10; &gt;Git 使用规范流程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/NeuOL/neuola-legacy/wiki/github%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97" target="_blank" rel="noopener"&#10; &gt;Github使用指南&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://git.oschina.net/progit/" target="_blank" rel="noopener"&#10; &gt;Pro Git（中文版）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ibm.com/developerworks/cn/linux/l-git/" target="_blank" rel="noopener"&#10; &gt;使用 Git 管理源代码&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/xirong/my-git/blob/master/git-workflow-tutorial.md" target="_blank" rel="noopener"&#10; &gt;Git工作流程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.runoob.com/git/git-branch.html" target="_blank" rel="noopener"&#10; &gt;Git 分支管理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.oschina.net/translate/a-successful-git-branching-model" target="_blank" rel="noopener"&#10; &gt;介绍一个成功的 Git 分支模型&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://gitbook.liuhui998.com/6_4.html" target="_blank" rel="noopener"&#10; &gt;从其他代码管理工具迁移到Git&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ruanyifeng.com/blog/2012/07/git.html" target="_blank" rel="noopener"&#10; &gt;Git分支管理策略&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://phphub.org/topics/576" target="_blank" rel="noopener"&#10; &gt;[Sever Hacks] 搭建私有 GitLab 代码托管服务器&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>MySQL秒杀优化</title><link>https://courages.us/%E7%A7%92%E6%9D%80/</link><pubDate>Sun, 12 Jul 2015 17:08:24 +0800</pubDate><guid>https://courages.us/%E7%A7%92%E6%9D%80/</guid><description>&lt;p&gt;今天学习了&lt;a class="link" href="http://weibo.com/dbatools" target="_blank" rel="noopener"&#10; &gt;楼方鑫先生&lt;/a&gt;的 &lt;a class="link" href="http://www.infoq.com/cn/presentations/seckill-solution-based-sql" target="_blank" rel="noopener"&#10; &gt;《基于SQL的秒杀解决方案》&lt;/a&gt;，讲解了如何定位和优化秒杀业务中问题。&lt;br&gt;&#10;首先介绍了库存业务，库存可以分为前端库存，后端库存，实体库存。秒杀时，存在的主要问题&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;库存数据不准确，下单、付款后，得知零库存；超卖或少卖&lt;/li&gt;&#10;&lt;li&gt;废单较多，只下单不付款，转化率低&lt;/li&gt;&#10;&lt;li&gt;热点商品，拖垮整个站&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;秒杀过程中，需要解决的技术点包括&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;余额减一&lt;/li&gt;&#10;&lt;li&gt;操作明细，方便追溯对账，防止一个帐号多次参与&lt;/li&gt;&#10;&lt;li&gt;完整事务，保障记录明细与扣减库存同时完成&lt;/li&gt;&#10;&lt;li&gt;数据落地，内存数据不可靠&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;针对库存技术要求，做了多个库存解决方案，比如Mysql + Read /Write Cache 。Read Cache方案不足是读有延迟影响用户体验；Write Cache方案存在多个APP写数据不一致性。Mysql + Cache + NoSQL方案则太复杂未实现。&lt;/p&gt;&#10;&lt;p&gt;于是又重新回到优化Mysql上。Mysql优势在于事务机制成熟，程序稳定。存在技术难点：单行并发，热点商品，瞬间压力，前一分钟，千万用户，容易堵塞，拖垮网站。于是从以下几个方面进行优化&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;事务优化，单行更新&lt;/li&gt;&#10;&lt;li&gt;并发优化，最大并发数&lt;/li&gt;&#10;&lt;li&gt;排队优化，抢同一商品&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;分析秒杀时的处理逻辑，扫描系统代码，发现大部分程序都在等待确认Update记录数，才提交事务。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;开启事务&lt;/li&gt;&#10;&lt;li&gt;Insert库存明细&lt;/li&gt;&#10;&lt;li&gt;Update库存余额&lt;/li&gt;&#10;&lt;li&gt;提交事务&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;在良好设计下，Mysql的Insert操作，不使用自增列是不会阻塞请求。但是Mysql的Update同一条记录是串行的，需要等远程客户端发送提交命令后才能释放锁，让其他会话继续。简单的更新操作，不考虑IO和锁冲突，一条语句执行的时间大约是0.1ms，一般条件下的网络时延为0.4-0.8ms，即等待事务提交通知的时间比真正SQL执行的时间长数倍。&lt;br&gt;&#10;于是扩展了SQL语法（&lt;a class="link" href="http://www.onexsoft.com/onesql" target="_blank" rel="noopener"&#10; &gt;OneSQL&lt;/a&gt;），指定在Update执行完后自动提交，不需要等待客户端发送提交命令，从而节约这一个网络来回的事务等待时间，提升网络性能。&lt;/p&gt;&#10;&lt;p&gt;秒杀时如果遇到大量请求需要进行排队，以免太多的请求拖垮Mysql&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;在应用层排队的缺点，应用需要改造，使用统一框架（需要考虑跨语言)，应用集群扩容时，控制不准确（连接数分配）&lt;/li&gt;&#10;&lt;li&gt;在Mysql排队的优点，应用改造极少，只需修改少量SQL语句，无需统一框架，排队精确，发挥InnoDB性能。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;于是开发了兼容Mysql的分布式数据访问层（&lt;a class="link" href="http://www.onexsoft.com/oneproxy" target="_blank" rel="noopener"&#10; &gt;OneProxy&lt;/a&gt;），为并发请求进行排队。&lt;/p&gt;&#10;&lt;p&gt;另外，还对热点商品进行独立数据库拆分和优化。目前，双十一前商品便已挂出，用户可以收藏或预购，对于商家而言可以准备更多商品；对于平台而言可以预先发现热点商品做优化。&lt;/p&gt;&#10;&lt;p&gt;总结，对于业务优化，需要循序渐进，深入了解业务逻辑和技术点，比较不同的解决方案，就算是平常的update操作也有优化空间；同时需要从其他方面进行特定优化，如高并发排队，热点数据分离等。&lt;/p&gt;&#10;&lt;p&gt;除了后端数据库优化，对于秒杀抽奖业务，问题的解决核心就是控制单位时间内的流量，使其不超过后端的处理能力。前端的做法包括&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;分批次（少量多次)进行秒杀&lt;/li&gt;&#10;&lt;li&gt;先玩游戏再抢购，如抽奖&lt;/li&gt;&#10;&lt;li&gt;随机过滤掉部分请求，仅部分进入系统，如1/10&lt;/li&gt;&#10;&lt;li&gt;阈值控制，一旦达到阈值，不再接收新请求&lt;/li&gt;&#10;&lt;li&gt;预约排号，未排号用户返回失败（用户分类）&lt;/li&gt;&#10;&lt;li&gt;验证码验证&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;另外，&lt;a class="link" href="http://www.onexsoft.com/oneproxy/oneproxy-connection-pool" target="_blank" rel="noopener"&#10; &gt;OneProxy 提供的连接池功能&lt;/a&gt;对于PHP非常有用。PHP运行在CGI下面，每一个请求到来便需要重新创建一个数据库连接与Mysql进行交互，并发量大量的情况下便会出现：too many connetion，乃至拖垮数据库：mysql server has gone away，影响其他业务。因此Mysql连接池，对于PHP显得非常重要。&lt;/p&gt;&#10;&lt;p&gt;更新：&lt;a class="link" href="http://www.infoq.com/cn/presentations/the-use-of-minority-languages-in-venture-company" target="_blank" rel="noopener"&#10; &gt;小米网在开发抢购系统&lt;/a&gt;的时候，最早使用PHP + Mysql碰到了一些问题，例如并发性能，数据一致性，在OneSQL上面都已经做了改进优化，只是小米自己使用Go语言重构，开发大秒系统（BigTap）。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.iteye.com/problems/101435" target="_blank" rel="noopener"&#10; &gt;限量秒杀等高并发活动的正确性如何保证？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://imysql.com/2014/06/07/mysql-percona-mariadb-onesql-tpcc-benchmark.shtml" target="_blank" rel="noopener"&#10; &gt;MySQL 5.6.17/Percona5.6.16/MariaDB 10.0.11/OneSQL 5.6.16 TpmC测试&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://coolshell.cn/articles/6470.html" target="_blank" rel="noopener"&#10; &gt;由12306.cn谈谈网站性能技术&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.csdn.net/article/2014-11-07/2822545" target="_blank" rel="noopener"&#10; &gt;“米粉节”背后的故事——小米网抢购系统开发实践&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.csdn.net/article/2014-11-28/2822858" target="_blank" rel="noopener"&#10; &gt;Web系统大规模并发——电商秒杀与抢购&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.onexsoft.com/oneproxy/oneproxy-connection-pool" target="_blank" rel="noopener"&#10; &gt;OneProxy : 如何给PHP页面以及其他Ruby/Python/Go程序添加连接池功能？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/LinkedDestiny/swoole-doc/blob/master/03.Timer%E5%AE%9A%E6%97%B6%E5%99%A8%E3%80%81%E5%BF%83%E8%B7%B3%E6%A3%80%E6%B5%8B%E5%8F%8ATask%E8%BF%9B%E9%98%B6%E5%AE%9E%E4%BE%8B%EF%BC%9Amysql%E8%BF%9E%E6%8E%A5%E6%B1%A0.md" target="_blank" rel="noopener"&#10; &gt;基于Swoole实现的Mysql连接池&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP性能分析之xhprof</title><link>https://courages.us/php%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E4%B9%8Bxhprof/</link><pubDate>Thu, 30 Apr 2015 21:37:08 +0800</pubDate><guid>https://courages.us/php%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E4%B9%8Bxhprof/</guid><description>&lt;p&gt;&lt;a class="link" href="https://courages.us/linux%e4%b8%8b%e4%bd%bf%e7%94%a8xdebug%e5%88%86%e6%9e%90php%e7%a8%8b%e5%ba%8f/" target="_blank" rel="noopener"&#10; &gt;xdebug&lt;/a&gt;讲到了使用xdebug对php程序进行性能分析，这里再介绍另外一个工具：&lt;a class="link" href="https://github.com/phacility/xhprof" target="_blank" rel="noopener"&#10; &gt;xhprof&lt;/a&gt;，facebook出品。xhprof是一个函数级别的分层性能报告工具，包括调用次数，阻塞时间，CPU时间和内存使用情况。&lt;br&gt;&#10;首先，下载并安装&lt;a class="link" href="https://pecl.php.net/package/xhprof" target="_blank" rel="noopener"&#10; &gt;xhprof扩展&lt;/a&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -zxvf xhprof-0.9.4.tgz &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd xhprof-0.9.4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/php/bin/phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --with-php-config&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/local/php/bin/php-config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#拷贝扩展&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/xhprof.so /usr/local/php/lib/php/extensions/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p /tmp/xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod &lt;span style="color:#ae81ff"&gt;755&lt;/span&gt; /tmp/xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chown www:www /tmp/xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;xhprof自带的界面工具比较简单，这里推荐使用另外一个UI：&lt;a class="link" href="http://xhprof.io/" target="_blank" rel="noopener"&#10; &gt;XHProf.io&lt;/a&gt;。下载解压到web目录下面，重命名/xhprof/includes/目录下的config.inc.sample.php为/xhprof/includes/config.inc.php，并更改文件：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;url_base&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;http://192.168.84.2:8502/&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;//本地的XHProf.io站点&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;url_static&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// When undefined, it defaults to $config[&amp;#39;url_base&amp;#39;] . &amp;#39;public/&amp;#39;. This should be absolute URL.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;pdo&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PDO&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;mysql:dbname=test;host=192.168.84.3;charset=utf8&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;root&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;root&amp;#39;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//本地的数据库配置，只支持PDO&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在test数据库上运行/xhprof/setup/database.sql，创建性能检测相关的表结构。&lt;br&gt;&#10;由于XHProf会去github上检测版本，国内访问较慢，建议不要检测。更改/xhprof/includes/bootstrap.inc.php如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;curl_setopt_array&lt;/span&gt;($ch, &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;CURLOPT_URL&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;http://192.168.84.2:8502/version.json&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;//本地的XHProf.io站点下面&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;CURLOPT_HEADER&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FALSE&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;CURLOPT_RETURNTRANSFER&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRUE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后更改php.ini配置，在最后加上以下内容：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[xhprof]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension=xhprof.so;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xhprof.output_dir=/tmp/xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Automatically add files before PHP document.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; XHProf.io站点下的prepend.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auto_prepend_file = /usr/local/nginx/xhprof/inc/prepend.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Automatically add files after PHP document.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; XHProf.io站点下的append.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auto_append_file = /usr/local/nginx/xhprof/inc/append.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;auto_prepend_file为每次php脚本运行前，自动加载并运行的文件；auto_append_file为每次php脚本运行后，自动加载并运行的文件。这样可以省去每次在需要检测的php文件里面写xhprof_enable/xhprof_disable等调用代码，不必更改原有代码（无侵入）。&lt;br&gt;&#10;注意：如果你访问了php页面却收集不到情况，可能是你的代码里面写了exit/die终止了程序执行，导致auto_append_file未加载执行，去掉exit/die就可以了。另外，如果提示：Unexpected system behaviour，可能是数据库连接不上，PDO、mbstring扩展未安装，响应数据里面带有错误信息的等等。&lt;/p&gt;&#10;&lt;p&gt;重启php-fpm：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#重启php-fpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill -USR2 &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;cat /usr/local/php/var/run/php-fpm.pid&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xhprof1.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xhprof1" class="gallery-image" data-flex-basis="765px" data-flex-grow="319" height="94" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xhprof1-300x94.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;访问该服务器上php页面，即可以在http://192.168.84.2:8502/看到检测情况。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xhprof5.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xhprof5" class="gallery-image" data-flex-basis="444px" data-flex-grow="185" height="162" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xhprof5-300x162.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xhprof4.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xhprof4" class="gallery-image" data-flex-basis="441px" data-flex-grow="184" height="163" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xhprof4-300x163.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xhprof6.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xhprof6" class="gallery-image" data-flex-basis="486px" data-flex-grow="202" height="148" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xhprof6-300x148.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;参数说明&lt;br&gt;&#10;Inclusive Time 包括子函数所有执行时间。&lt;br&gt;&#10;Exclusive Time/Self Time 函数执行本身花费的时间，不包括子树执行时间。&lt;br&gt;&#10;Wall Time 花去了的时间或挂钟时间。&lt;br&gt;&#10;CPU Time 用户耗的时间+内核耗的时间&lt;br&gt;&#10;Inclusive CPU 包括子函数一起所占用的CPU&lt;br&gt;&#10;Exclusive CPU 函数自身所占用的CPU&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://blog.snsgou.com/post-278.html" target="_blank" rel="noopener"&#10; &gt;给CentOS6.3 + PHP5.3 安装PHP性能测试工具 XHProf-0.9.2&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/gajus/xhprof.io/blob/master/INSTALL.md" target="_blank" rel="noopener"&#10; &gt;xhprof.io/INSTALL.md&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/ini.core.php#ini.auto-append-file" target="_blank" rel="noopener"&#10; &gt;php auto_append_file&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>开启Firephp时Nginx PHP-FPM下502错误解决</title><link>https://courages.us/%E5%BC%80%E5%90%AFfirephp%E6%97%B6nginx-php-fpm%E4%B8%8B502%E9%94%99%E8%AF%AF%E8%A7%A3%E5%86%B3/</link><pubDate>Sun, 03 Aug 2014 10:53:25 +0800</pubDate><guid>https://courages.us/%E5%BC%80%E5%90%AFfirephp%E6%97%B6nginx-php-fpm%E4%B8%8B502%E9%94%99%E8%AF%AF%E8%A7%A3%E5%86%B3/</guid><description>&lt;p&gt;在自己的电脑上调试的好好的，部署到Linux Nginx环境的时候却发现有些PHP页面在Firefox下面会返回502，在IE下面却是正常的，甚至在chrome下面也会出现502。顺着Nginx，Firefox这两个关键字，终于找到原因：原来是开启Firephp(chrome装了webug)时，Firephp的调试信息会写入的请求头里面，导致Nginx的FastCGI缓冲区超出，从而返回502。在自己的电脑上之所以不会是因为使用的是Apache。&lt;br&gt;&#10;于是顺着其他人的解答修改了nginx.conf中fastcig相关的参数：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fastcgi_buffer_size 1024k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fastcgi_buffers &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 512k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fastcgi_busy_buffers_size 1024k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fastcgi_temp_file_write_size 1024k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一开始这些参数是256，后来改成了512还是有部分页面会出现502，再改成1024终于好了。&lt;/p&gt;&#10;&lt;p&gt;检查Nginx的配置文件，并重启：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@webserver sbin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./nginx -t&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@webserver sbin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./nginx -s reload&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@webserver sbin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://serverfault.com/questions/201632/nginx-php5-fpm-repeated-cut-outs-502" target="_blank" rel="noopener"&#10; &gt;Nginx + PHP5-FPM repeated cut outs 502&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://shiki.me/blog/firephp-on-nginx-502-bad-gateway/" target="_blank" rel="noopener"&#10; &gt;FirePHP on Nginx: 502 Bad Gateway&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://britg.com/2009/06/16/nginx-proxies-with-firephp/" target="_blank" rel="noopener"&#10; &gt;Nginx Proxies with FirePHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://letle.iteye.com/blog/1049265" target="_blank" rel="noopener"&#10; &gt;Nginx提示502和504错误的终极解决方案&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.howtocn.org/nginx:nginx%E6%A8%A1%E5%9D%97%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C%E4%B8%AD%E6%96%87%E7%89%88:standardhttpmodules:fastcgi" target="_blank" rel="noopener"&#10; &gt;FastCGI模块（FastCGI）&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Nginx做简单的反向代理</title><link>https://courages.us/nginx%E5%81%9A%E7%AE%80%E5%8D%95%E7%9A%84%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86/</link><pubDate>Fri, 15 Feb 2013 17:52:35 +0800</pubDate><guid>https://courages.us/nginx%E5%81%9A%E7%AE%80%E5%8D%95%E7%9A%84%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86/</guid><description>&lt;p&gt;&lt;a class="link" href="http://nginx.org/cn/" target="_blank" rel="noopener"&#10; &gt;Nginx&lt;/a&gt;是一个HTTP和反向代理服务器，可做为反向代理实现负载均衡的例子，也可以作为代理服务器，也经常作为web服务器使用。如果一台服务器装有多个web服务器则必须监听多个端口，对于用户的访问将是不友好，则需要一个统一的前端来进行分发。本文只是简单的利用Nginx作为前端代理服务器，代理不同的后端服务器:IIS和Apache，实现不同的域名解析至不同的服务器。&lt;/p&gt;&#10;&lt;p&gt;首先更改IIS的监听端口为8000，Apache的监听端口为9000，保证Nginx占有80端口和443端口。然后更改nginx.conf添加以下内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name iis.localhost;#要代理的域名&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:8000/;#内部服务器实际地址和监听端口&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_redirect off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Real-IP $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name apache.localhost;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:9000/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_redirect off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Real-IP $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进阶操作，可按照参照&lt;a class="link" href="http://www.vpsmm.com/blog/nginx-proxy-and-all-cache-config" target="_blank" rel="noopener"&#10; &gt;此文&lt;/a&gt;设置前端缓存，注意以下内容须放入http{}内&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_body_buffer_size 512k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_connect_timeout 5;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_read_timeout 60;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_send_timeout 5;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_buffer_size 16k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_buffers 4 64k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_busy_buffers_size 128k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_temp_file_write_size 128k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_temp_path D:/nginx/temp;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_cache_path D:/nginx/cache levels=1:2 keys_zone=cache_one:256m inactive=7d max_size=1g;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再修改server中location{}的缓存设置如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_cache cache_one;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_cache_valid 200 304 3d;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;expires 10d;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/omohe/article/details/4335765" target="_blank" rel="noopener"&#10; &gt;nginx做为反向代理实现负载均衡的例子&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.vpsmm.com/blog/nginx-proxy-and-all-cache-config" target="_blank" rel="noopener"&#10; &gt;Nginx反向代理&amp;amp;前端全缓存相关配置教程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ha97.com/5119.html" target="_blank" rel="noopener"&#10; &gt;（总结）Nginx与Apache、Tomcat、Resin动静分离核心配置&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>