<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nginx on 勇气</title><link>https://courages.us/category/nginx/</link><description>Recent content in Nginx 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/nginx/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>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>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>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>基于Docker的Nginx + PHP-FPM + Phalcon镜像</title><link>https://courages.us/%E6%9E%84%E5%BB%BA%E5%9F%BA%E4%BA%8Edocker%E7%9A%84nginx-php-fpm-phalcon%E9%95%9C%E5%83%8F/</link><pubDate>Wed, 28 Sep 2016 23:34:40 +0800</pubDate><guid>https://courages.us/%E6%9E%84%E5%BB%BA%E5%9F%BA%E4%BA%8Edocker%E7%9A%84nginx-php-fpm-phalcon%E9%95%9C%E5%83%8F/</guid><description>&lt;p&gt;&lt;a class="link" href="https://courages.us/ubuntu-16-04-%e4%b8%8a%e5%ae%89%e8%a3%85docker/" target="_blank" rel="noopener"&#10; &gt;上一篇&lt;/a&gt;简单介绍了Docker的安装，运行，这一篇来构建一个基于Nginx和PHP-FPM的Phalcon镜像。在官方找了以下，单独的Nginx和PHP镜像更加流行，混合的反倒不是很受欢迎。其实官方并不提倡在一个容器里面运行多个服务，最好是一个容器只对外提供一个服务：一个容器启动时仅仅运行一个命令（其实里面可以包含多个），也方便部署扩展升级。多个服务之间可以使用&lt;a class="link" href="https://github.com/yeasy/docker_practice/blob/master/compose/yaml_file.md" target="_blank" rel="noopener"&#10; &gt;Docker Compose&lt;/a&gt;来管理。但是Docker并不阻止创建包含多个服务器的镜像，为了方便，所以我们仍然可以自己构建。&lt;br&gt;&#10;构建镜像可以有好几种方式，比如基于&lt;a class="link" href="https://hub.docker.com/_/alpine/" target="_blank" rel="noopener"&#10; &gt;Alpine Linux&lt;/a&gt;或&lt;a class="link" href="https://github.com/phusion/baseimage-docker" target="_blank" rel="noopener"&#10; &gt;phusion/baseimage-docker&lt;/a&gt;构建，或者基于Ubuntu，CentOS等构建，又或者在PHP，Nginx的基础镜像上构建。注意：如果要采用Ubuntu或者CentOS构建，可能需要一些额外的&lt;a class="link" href="http://phusion.github.io/baseimage-docker/" target="_blank" rel="noopener"&#10; &gt;工作&lt;/a&gt;，以便保持镜像轻量稳定运行。&lt;br&gt;&#10;这里采用已有的&lt;a class="link" href="https://hub.docker.com/r/richarvey/nginx-php-fpm/" target="_blank" rel="noopener"&#10; &gt;richarvey/nginx-php-fpm&lt;/a&gt;来构建，它是一个基于&lt;a class="link" href="https://hub.docker.com/_/nginx/" target="_blank" rel="noopener"&#10; &gt;Nginx官方镜像&lt;/a&gt;来构建的。&lt;br&gt;&#10;从&lt;a class="link" href="https://github.com/ngineered/nginx-php-fpm" target="_blank" rel="noopener"&#10; &gt;Github&lt;/a&gt;上拉取相关文件从Dockerfile构建：&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 git clone https://github.com/ngineered/nginx-php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo docker build -t nginx-php-fpm:latest .&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关于Dockerfile的相关解释，可以参考&lt;a class="link" href="https://github.com/yeasy/docker_practice/blob/master/dockerfile/basic_structure.md" 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;$ sudo docker pull richarvey/nginx-php-fpm&#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 docker run -d richarvey/nginx-php-fpm&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;root@thinkpad:~# 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;nginx-php-fpm latest 4fc9ac9f2945 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; hours ago 228.5 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx mainline-alpine 00bc1e841a8f &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; days ago 54.21 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的mainline-alpine是指基于&lt;a class="link" href="https://alpinelinux.org/" target="_blank" rel="noopener"&#10; &gt;Alpine Linux&lt;/a&gt;构建的。Alpine Linux是一个仅有5M大小的linux系统，采用apk add/search来安装/查找相应软件，有许多镜像都是基于它构建的，官方PHP镜像也有基于它构建的Docker镜像。&lt;br&gt;&#10;然后运行nginx-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;root@thinkpad:~# docker run --name web -d richarvey/nginx-php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;docker inspect命令用来查看容器的相关信息，查看下分配的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;root@thinkpad:~# docker inspect web | grep IPAddress&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;SecondaryIPAddresses&amp;#34;&lt;/span&gt;: null,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;IPAddress&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;172.17.0.2&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;IPAddress&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;172.17.0.2&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在浏览器里面访问：http://172.17.0.2/就可以看到phpinfo的页面。到这里，Nginx + PHP的web容器就已经运行起来了，对应的Nginx和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;root@thinkpad:~# ps aux | grep nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;18167&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;13696&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4300&lt;/span&gt; pts/6 S 01:47 0:00 nginx: master process /usr/sbin/nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18168&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18169&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18170&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18171&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18172&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;18190&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;21292&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1012&lt;/span&gt; pts/18 S+ 01:47 0:00 grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# ps aux | grep php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;18166&lt;/span&gt; 0.0 0.2 &lt;span style="color:#ae81ff"&gt;167880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;23364&lt;/span&gt; pts/6 S 01:47 0:00 php-fpm: master process &lt;span style="color:#f92672"&gt;(&lt;/span&gt;/etc/php5/php-fpm.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;systemd+ &lt;span style="color:#ae81ff"&gt;18173&lt;/span&gt; 0.0 0.1 &lt;span style="color:#ae81ff"&gt;167880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8620&lt;/span&gt; pts/6 S 01:47 0:00 php-fpm: pool www&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18174&lt;/span&gt; 0.0 0.1 &lt;span style="color:#ae81ff"&gt;167880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8620&lt;/span&gt; pts/6 S 01:47 0:00 php-fpm: pool www&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18175&lt;/span&gt; 0.0 0.1 &lt;span style="color:#ae81ff"&gt;167880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8620&lt;/span&gt; pts/6 S 01:47 0:00 php-fpm: pool www&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;18192&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;21292&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1032&lt;/span&gt; pts/18 S+ 01:47 0:00 grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下来要为这个容器添加Phalcon扩展。首先要进入容器里面，使用docker attach命令进入：&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;root@thinkpad:~# docker attach web&#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;root@thinkpad:~# 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;94176348a939 nginx-php-fpm &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; seconds 80/tcp, 443/tcp web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个容器启动的时候运行的是start.sh这个脚本，这个脚本运行了&lt;a class="link" href="http://supervisord.org/" target="_blank" rel="noopener"&#10; &gt;Supervisor&lt;/a&gt;工具。于是重新启动容器，运行/bin/bash&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;root@thinkpad:~# docker stop web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#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;root@thinkpad:~# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#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;root@thinkpad:~# docker run --name web -d -t -i nginx-php-fpm /bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ea21e10df702644a83ed75930b30c7764a786c4feabdf17cd868f86640137c47&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# 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;ea21e10df702 nginx-php-fpm &lt;span style="color:#e6db74"&gt;&amp;#34;/bin/bash&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; seconds 80/tcp, 443/tcp web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker attach web&#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;bash-4.3# ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bin etc lib media proc run srv sys usr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dev home linuxrc mnt root sbin start.sh tmp var&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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;bash-4.3# apk --no-cache add php5-dev&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add gcc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add autoconf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add libc-dev&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.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;1/2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Installing musl-dev &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.1.14-r12&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;2/2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Installing libc-dev &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.7-r0&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;OK: &lt;span style="color:#ae81ff"&gt;334&lt;/span&gt; MiB in &lt;span style="color:#ae81ff"&gt;106&lt;/span&gt; packages&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译安装Phalcon：&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;bash-4.3# cd /home&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# git clone --depth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; git://github.com/phalcon/cphalcon.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# cd cphalcon/build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# ./install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# ls -la /usr/lib/php5/modules/ | grep phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rwxr-xr-x &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;5045264&lt;/span&gt; Sep &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; 17:34 phalcon.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# cd /etc/php5/conf.d/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# vi phalcon.ini&#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;#extension=phalcon.so&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;bash-4.3# php -i | grep phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/etc/php5/conf.d/phalcon.ini,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; enabled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.db.escape_identifiers &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.db.force_casting &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.cast_on_hydrate &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.column_renaming &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.enable_implicit_joins &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.enable_literals &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.events &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.exception_on_failed_save &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.ignore_unknown_columns &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.late_state_binding &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.not_null_validations &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.virtual_foreign_keys &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;OLDPWD &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; /home/cphalcon/build&#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;&amp;#34;OLDPWD&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; /home/cphalcon/build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;_ENV&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;OLDPWD&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; /home/cphalcon/build&#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;bash-4.3# cd /home&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#删除各种不必要的东西，比如gcc&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# rm -rf cphalcon/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exit&#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;root@thinkpad:~# docker ps -l&#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;ea21e10df702 nginx-php-fpm &lt;span style="color:#e6db74"&gt;&amp;#34;/bin/bash&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; minutes ago Exited &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; seconds ago web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker commit ea2 nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sha256:bb388df328ecc33fac02dba69759d5c992a145f650a0e5b20ca29a4b122fa933&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;docker commit命令可以用来提交变更，ea2是container id的前三位，也可以写全；然后跟的是要提交的镜像。这里提交到phalcon这个标签下，以便与原来的区分开。查看所有镜像，发现有两个不同的标签：&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;root@thinkpad:~# 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;nginx-php-fpm phalcon bb388df328ec &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds ago 364.4 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx-php-fpm latest 4fc9ac9f2945 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; hours ago 228.5 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;采用新镜像来运行，这里要讲程序运行入口改回/start.sh，以便能正常启动Nginx和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;root@thinkpad:~# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name web -d -t -i nginx-php-fpm:phalcon /start.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;deecb19467cda2676b24248e3f55970a2481255c6022a80ffbf5087792ccb559&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# 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;deecb19467cd nginx-php-fpm:phalcon &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; seconds 80/tcp, 443/tcp web&#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;root@thinkpad:~# docker stop web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps -l&#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;c7600e62733d nginx-php-fpm:phalcon &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; seconds ago Exited &lt;span style="color:#f92672"&gt;(&lt;/span&gt;137&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; seconds ago web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker commit c76 nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sha256:1c97ee169a551dd8441f42b40beafd102c71f3e887e2317dc11ce0ef136ceaf0&#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;root@thinkpad:~# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name web -d -t -i nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cb5b0c9e55913a538539e46c53ac7905b21def84a05eb00ef81c4b500853576c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# 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;cb5b0c9e5591 nginx-php-fpm:phalcon &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; seconds 80/tcp, 443/tcp web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问http://172.17.0.2/，便可以在页面找到phalcon扩展。&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;root@thinkpad:~# docker stop web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name web -d -t -i -v /home/docker/nginx-php-fpm/src:/var/www/html/ nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ffd64793fe8e7a2a95b68f514e221b7ec3b6cadfe668c016f55a7bb6d48bc702&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;-v参数可以用来挂载目录或者文件，可以又多个-v参数。&lt;br&gt;&#10;刚才容器里面做的那些已经添加到&lt;a class="link" href="https://github.com/llitllie/nginx-php-fpm-phalcon" target="_blank" rel="noopener"&#10; &gt;Dockerfile里&lt;/a&gt;面去，你直接使用它来构建。&lt;br&gt;&#10;至此Nginx + PHP-FPM + Phalcon镜像构建完成，介绍绍了如何进入容器，提交变更，网络访问和文件挂载。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://phusion.github.io/baseimage-docker/" target="_blank" rel="noopener"&#10; &gt;A minimal Ubuntu base image modified for Docker-friendliness&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://hub.docker.com/r/eboraas/phalcon/~/dockerfile/" target="_blank" rel="noopener"&#10; &gt;eboraas/phalcon&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dockone.io/article/117" target="_blank" rel="noopener"&#10; &gt;基于Docker的PHP开发环境&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.newmediacampaigns.com/blog/docker-for-php-developers" target="_blank" rel="noopener"&#10; &gt;Docker for PHP Developers&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://avnpc.com/pages/build-php-develop-env-by-docker" target="_blank" rel="noopener"&#10; &gt;Docker在PHP项目开发环境中的应用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/yeasy/docker_practice/blob/master/cases/supervisor.md" target="_blank" rel="noopener"&#10; &gt;使用 Supervisor 来管理进程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/php-%e6%a1%86%e6%9e%b6phalcon/" target="_blank" rel="noopener"&#10; &gt;PHP C扩展框架Phalcon&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/news/2016/01/Alpine-Linux-5M-Docker" target="_blank" rel="noopener"&#10; &gt;Alpine Linux，一个只有5M的Docker镜像&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP C扩展框架Phalcon</title><link>https://courages.us/php-%E6%A1%86%E6%9E%B6phalcon/</link><pubDate>Thu, 30 Jul 2015 13:33:59 +0800</pubDate><guid>https://courages.us/php-%E6%A1%86%E6%9E%B6phalcon/</guid><description>&lt;p&gt;&lt;a class="link" href="https://phalconphp.com/zh/" target="_blank" rel="noopener"&#10; &gt;Phalcon&lt;/a&gt;是一个C语言写的高性能PHP框架，相比PHP写的框架，它作为PHP的扩展在进程开启时便加载了，节省了每一次请求时的类库加载、MVC框架分派的开销。前面提到的使用&lt;a class="link" href="https://courages.us/php-%e6%89%a9%e5%b1%95%e5%bc%80%e5%8f%91%e4%b9%8bzephir/" target="_blank" rel="noopener"&#10; &gt;Zephir&lt;/a&gt;来开发PHP扩展也是这个项目贡献的。&lt;br&gt;&#10;在CentOS 上安装Phalcon，因为之前安装过zephire了，所以直接下载cphalcon来编译安装就可以了，可以参照&lt;a class="link" href="https://docs.phalconphp.com/en/latest/reference/install.html#linux-solaris" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;安装所需其他lib&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 --depth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; git://github.com/phalcon/cphalcon.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd cphalcon/build/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ./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;sudo vim /etc/php.d/phalcon.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建phalcon.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;[phalcon]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension=phalcon.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里单独把phalcon.ini单独配置，是因为Phalcon扩展加载要在PDO扩展之后，而我的PDO也是单独配置的。如果不是的话会提示这个错误：&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;$ php -m | grep phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP Warning: PHP Startup: Unable to load dynamic library &lt;span style="color:#e6db74"&gt;&amp;#39;/usr/lib64/php/modules/phalcon.so&amp;#39;&lt;/span&gt; - /usr/lib64/php/modules/phalcon.so: undefined symbol: php_pdo_get_dbh_ce in Unknown on line &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;与&lt;a class="link" href="http://framework.zend.com/" target="_blank" rel="noopener"&#10; &gt;Zend Framwork&lt;/a&gt;类似，Phalcon也提供&lt;a class="link" href="https://github.com/phalcon/phalcon-devtools" 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;git clone https://github.com/phalcon/phalcon-devtools.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd phalcon-devtools&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./phalcon.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ln -s ~/phalcon-devtools/phalcon.php /usr/bin/phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo chmod ugo+x /usr/bin/phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon commands&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，这个开发工具也是需要依赖Phalcon扩展的，否则会提示&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;$ phalcon command&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP Fatal error: Class &lt;span style="color:#e6db74"&gt;&amp;#39;Phalcon\Script&amp;#39;&lt;/span&gt; not found in /home/vagrant/phalcon-devtools/phalcon.php on line &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;PHP Stack trace:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP 1. &lt;span style="color:#f92672"&gt;{&lt;/span&gt;main&lt;span style="color:#f92672"&gt;}()&lt;/span&gt; /home/vagrant/phalcon-devtools/phalcon.php:0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成一个测试项目store&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;phalcon scaffold store&#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-text" data-lang="text"&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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 8005;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name store.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; index index.php index.html index.htm;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set $root_path &amp;#39;/usr/share/nginx/html/tutorial/store/public&amp;#39;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root $root_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; try_files $uri $uri/ @rewrite;&#10;&lt;/span&gt;&lt;/span&gt;&lt;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 @rewrite {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rewrite ^/(.*)$ /index.php?_url=https://courages.us/$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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location ~ \.php {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_pass unix:/tmp/php5-fpm.sock;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_index /index.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; include fastcgi.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; fastcgi_split_path_info ^(.+\.php)(/.+)$;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_param PATH_INFO $fastcgi_path_info;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;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; location ~* ^/(css|img|js|flv|swf|download)/(.+)$ {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root $root_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; location ~ /\.ht {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deny 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;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问一下192.168.33.14:8005，提示：Access denied。。。查看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@vagrant nginx&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# tail -n 20 error.log&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2015/07/28 03:41:42 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;error&lt;span style="color:#f92672"&gt;]&lt;/span&gt; 7343#0: *1 FastCGI sent in stderr: &lt;span style="color:#e6db74"&gt;&amp;#34;Access to the script &amp;#39;/usr/share/nginx/html/tutorial/store/public&amp;#39; has been denied (see security.limit_extensions)&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; reading response header from upstream, client: 192.168.33.1, server: store.localhost, request: &lt;span style="color:#e6db74"&gt;&amp;#34;GET / HTTP/1.1&amp;#34;&lt;/span&gt;, upstream: &lt;span style="color:#e6db74"&gt;&amp;#34;fastcgi://unix:/tmp/php5-fpm.sock:&amp;#34;&lt;/span&gt;, host: &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.14:8005&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一开始还以为是PHP-FPM配置security.limit_extensions引起的，后来发现这个这个参数默认就是注释掉的，没限制。 最后在&lt;a class="link" href="http://askubuntu.com/questions/164627/nginx-php-fpm-access-denied-error" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;找到答案：原来是之前&lt;a class="link" href="https://courages.us/php%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96%e4%b9%8bnginxphp-fpm/" target="_blank" rel="noopener"&#10; &gt;安装Nginx&lt;/a&gt;时配置了：cgi.fix_pathinfo=0，将它改回1（默认值）就可以了。当这个参数为1时，会把 PATH_TRANSLATED 转换为 SCRIPT_FILENAME。当然把这个参数去掉也是可以的&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; ;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;&#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;sudo service nginx restart&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与其他PHP框架一样，Phalcon 支持MVC应用开发，提供了诸多组件如，数据库，缓存，队列等。&lt;br&gt;&#10;&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/di.html" target="_blank" rel="noopener"&#10; &gt;Phalcon\DI&lt;/a&gt; 作为全局的服务管理，用于服务注册，比如数据库，缓存，文件等。将这些资源统一起来管理，以便其他地方可以调用，各个需要的地方不再需要是new 一个对象，解除耦合关系。&lt;br&gt;&#10;Phalcon\Events\Manager作为全局的事件管理，用于事件注册，触发，以便自定义消息通知，如数据库查询事件，初始化事件。&lt;br&gt;&#10;Phalcon还有一个比较有特色的地方支持注释解析: Phalcon\Annotations 。&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/annotations.html" target="_blank" rel="noopener"&#10; &gt;官方教程&lt;/a&gt;举例如何使用注释做输出缓存。首先在Dispatcher服务中注册一个监听dispactch事件的缓存插件&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;$di[&lt;span style="color:#e6db74"&gt;&amp;#39;dispatcher&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&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; $eventsManager &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;\Phalcon\Events\Manager&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;// 添加插件到dispatch事件中&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $eventsManager&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;attach&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dispatch&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CacheEnablerPlugin&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; $dispatcher &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;\Phalcon\Mvc\Dispatcher&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dispatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setEventsManager&lt;/span&gt;($eventsManager);&#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; $dispatcher;&#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;/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:#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; * 为视图启动缓存，如果被执行的action带有@Cache 注释单元。&#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; */&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;CacheEnablerPlugin&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Phalcon\Mvc\User\Plugin&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; * 这个事件在dispatcher中的每个路由被执行前执行&#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; */&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;beforeExecuteRoute&lt;/span&gt;($event, $dispatcher)&#10;&lt;/span&gt;&lt;/span&gt;&lt;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;// 解析目前访问的控制的方法的注释&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $annotations &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;annotations&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getMethod&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dispatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getActiveController&lt;/span&gt;(),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dispatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getActiveMethod&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;// 检查是否方法中带有注释名称‘Cache’的注释单元&#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;if&lt;/span&gt; ($annotations&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;has&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Cache&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;// 这个方法带有‘Cache’注释单元&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $annotation &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $annotations&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Cache&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;// 获取注释单元的‘lifetime’参数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $lifetime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $annotation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getNamedParameter&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;lifetime&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; $options &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;lifetime&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $lifetime);&#10;&lt;/span&gt;&lt;/span&gt;&lt;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;// 检查注释单元中是否有用户定义的‘key’参数&#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;if&lt;/span&gt; ($annotation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hasNamedParameter&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $options[&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $annotation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getNamedParameter&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;key&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:#75715e"&gt;// 为当前dispatcher访问的方法开启cache&#10;&lt;/span&gt;&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;view&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cache&lt;/span&gt;($options);&#10;&lt;/span&gt;&lt;/span&gt;&lt;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;}&#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;&#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;NewsController&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Phalcon\Mvc\Controller&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;indexAction&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:#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; * This is a comment&#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; * @Cache(lifetime=86400)&#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; &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;showAllAction&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;view&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;article&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Articles&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;find&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; * This is a comment&#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; * @Cache(key=&amp;#34;my-key&amp;#34;, lifetime=86400)&#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; &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;showAction&lt;/span&gt;($slug)&#10;&lt;/span&gt;&lt;/span&gt;&lt;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;view&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;article&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Articles&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;findFirstByTitle&lt;/span&gt;($slug);&#10;&lt;/span&gt;&lt;/span&gt;&lt;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;为Action增加了缓存，但对Action的代码改动为0（无侵入）并且非常简洁。&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/models-metadata.html#annotations-strategy" 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-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;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Phalcon\Mvc\Model&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;Robots&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Model&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; * @Primary&#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; * @Identity&#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; * @Column(type=&amp;#34;integer&amp;#34;, nullable=false)&#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; &lt;span style="color:#66d9ef"&gt;public&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:#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; * @Column(type=&amp;#34;string&amp;#34;, length=70, nullable=false)&#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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;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; * @Column(type=&amp;#34;string&amp;#34;, length=32, nullable=false)&#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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $type;&#10;&lt;/span&gt;&lt;/span&gt;&lt;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; * @Column(type=&amp;#34;integer&amp;#34;, nullable=false)&#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; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $year;&#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;路由解析也可以使用RouterAnnotations反射来实现&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;?&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:#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; * @RoutePrefix(&amp;#34;/api/products&amp;#34;)&#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;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProductsController&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; * @Get(&amp;#34;/&amp;#34;)&#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; &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;indexAction&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:#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; * @Get(&amp;#34;/edit/{id:[0-9]+}&amp;#34;, name=&amp;#34;edit-robot&amp;#34;)&#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; &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;editAction&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; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;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; * @Route(&amp;#34;/save&amp;#34;, methods={&amp;#34;POST&amp;#34;, &amp;#34;PUT&amp;#34;}, name=&amp;#34;save-robot&amp;#34;)&#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; &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;saveAction&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:#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; * @Route(&amp;#34;/delete/{id:[0-9]+}&amp;#34;, methods=&amp;#34;DELETE&amp;#34;,&#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; * conversors={id=&amp;#34;MyConversors::checkId&amp;#34;})&#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; &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;deleteAction&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; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;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;infoAction&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; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;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://Java%20annotation" target="_blank" rel="noopener"&#10; &gt;Java annotation&lt;/a&gt;有点像？之前介绍的PHPUnit，Zend Framework，还有&lt;a class="link" href="https://symfony.com/" target="_blank" rel="noopener"&#10; &gt;Symfony 2&lt;/a&gt; 和 &lt;a class="link" href="http://www.doctrine-project.org/" target="_blank" rel="noopener"&#10; &gt;Doctrine 2&lt;/a&gt;已经在PHP层面上支持，使用&lt;a class="link" href="http://php.net/manual/zh/reflectionclass.getdoccomment.php" target="_blank" rel="noopener"&#10; &gt;ReflectionClass&lt;/a&gt;便可实现。&lt;br&gt;&#10;Phalcon也支持创&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/cli.html" target="_blank" rel="noopener"&#10; &gt;建命令行应用&lt;/a&gt;，可以将PHP应用打包成Phar，直接运行，也可以结合&lt;a class="link" href="http://www.if-not-true-then-false.com/2010/php-class-for-coloring-php-command-line-cli-scripts-output-php-output-colorizing-using-bash-shell-colors/" 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="https://docs.phalconphp.com/zh/latest/reference/nginx.html" target="_blank" rel="noopener"&#10; &gt;Nginx 安装说明（Nginx Installation Notes）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://forum.phalconphp.com/discussion/1899/can-t-upgrade-to-phalcon-1-3-0" target="_blank" rel="noopener"&#10; &gt;Can’t upgrade to Phalcon 1.3.0&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://askubuntu.com/questions/164627/nginx-php-fpm-access-denied-error" target="_blank" rel="noopener"&#10; &gt;Nginx/PHP-FPM “Access denied.” error&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/23390531/access-denied-403-for-php-files-with-nginx-php-fpm" target="_blank" rel="noopener"&#10; &gt;Access denied (403) for PHP files with Nginx + PHP-FPM&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/tools.html" target="_blank" rel="noopener"&#10; &gt;Phalcon 开发工具（Phalcon Developer Tools）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/15808688/ide-autocomplete-for-phalconphp" target="_blank" rel="noopener"&#10; &gt;IDE autocomplete for PhalconPHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/rdohms/annotations-in-php-they-exist" target="_blank" rel="noopener"&#10; &gt;Annotations in PHP: They Exist&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://theunraveler.com/blog/2012/php-annotations-are-a-horrible-idea/" target="_blank" rel="noopener"&#10; &gt;PHP Annotations Are a Horrible Idea&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.if-not-true-then-false.com/2010/php-class-for-coloring-php-command-line-cli-scripts-output-php-output-colorizing-using-bash-shell-colors/" target="_blank" rel="noopener"&#10; &gt;PHP CLI Colors – PHP Class Command Line Colors (bash)&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>CentOS上安装Nginx+PHP-FPM</title><link>https://courages.us/php%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E4%B9%8Bnginxphp-fpm/</link><pubDate>Sun, 10 May 2015 11:06:08 +0800</pubDate><guid>https://courages.us/php%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E4%B9%8Bnginxphp-fpm/</guid><description>&lt;p&gt;&lt;a class="link" href="http://nginx.org/en/" target="_blank" rel="noopener"&#10; &gt;Nginx&lt;/a&gt;是一个高性能、轻量级的HTTP服务器，占用内存少，稳定性高，也可做为&lt;a class="link" href="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/" target="_blank" rel="noopener"&#10; &gt;反向代理服务器&lt;/a&gt;。Nginx采用事件驱动，在Linux操作系统下，Nginx使用epoll事件模型，充分使用异步逻辑，削减了上下文调度开销，并发服务能力更强。&lt;/p&gt;&#10;&lt;p&gt;PHP-FPM是PHP的FastCGI 进程管理器，具有一些高级特性，将PHP进程管理与Web服务器分开，可以分开部署在不同机器上，监听不同的端口和使用不同的 php.ini 配置文件。&lt;/p&gt;&#10;&lt;p&gt;PHP-FPM特性之一：&lt;a class="link" href="http://php.net/manual/zh/function.fastcgi-finish-request.php" target="_blank" rel="noopener"&#10; &gt;fastcgi_finish_request&lt;/a&gt;能够在请求完成和刷新数据后，继续在后台执行耗时的工作（录入视频转换、统计处理等），达到分离执行后台任务而又不阻塞PHP快速响应，可作为PHP性能优化点。&lt;/p&gt;&#10;&lt;p&gt;PHP-FPM另一特性：可以记录请求当中慢响应的日志，类似Mysql满日志，包括文件名，函数名，行号等，可用于分析PHP的性能问题。&lt;/p&gt;&#10;&lt;p&gt;在Apache + mod_php下，每一个请求，Apache便会启动一个进程并加载php解释器来处理。在Nginx + PHP-FPM下，Nginx将PHP请求和环境变量通过socket传递给FastCGI进程；将静态资源请求则缓存到本地并返回。FastCGI 进程管理器采用固定静态（或动态）的子进程来处理请求，占用内存少，具有更好的扩展能力。&lt;/p&gt;&#10;&lt;p&gt;在CentOs 6.4上安装Nginx和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;yum search nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo chkconfig --levels &lt;span style="color:#ae81ff"&gt;235&lt;/span&gt; nginx on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo service nginx start&#10;&lt;/span&gt;&lt;/span&gt;&lt;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 search fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install php54-fpm&#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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&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;; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP&amp;#39;s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; of zero causes PHP to behave as before. Default is 1. You should fix your scripts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; http://www.php.net/manual/en/ini.core.php#ini.cgi.fix-pathinfo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cgi.fix_pathinfo=0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&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;chkconfig --levels &lt;span style="color:#ae81ff"&gt;235&lt;/span&gt; php-fpm on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;service php-fpm start&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改Nginx worker_processes配置&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/nginx/nginx.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&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;worker_processes 4;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改Nginx 配置以便处理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;sudo vim /etc/nginx/conf.d/default.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&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;server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80 default_server;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name _;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #charset koi8-r;&#10;&lt;/span&gt;&lt;/span&gt;&lt;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 logs/host.access.log main;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # Load configuration files for the default server block.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /etc/nginx/default.d/*.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 / {&#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; index index.html index.htm;&#10;&lt;/span&gt;&lt;/span&gt;&lt;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; error_page 404 /404.html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location = /404.html {&#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; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # redirect server error pages to the static page /50x.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error_page 500 502 503 504 /50x.html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location = /50x.html {&#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; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;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 the PHP scripts to Apache listening on 127.0.0.1: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; #location ~ \.php$ {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # proxy_pass http://127.0.0.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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000&#10;&lt;/span&gt;&lt;/span&gt;&lt;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 ~ \.php$ {&#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; #fastcgi_pass 127.0.0.1:9000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_pass unix:/tmp/php5-fpm.sock;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_index index.php;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include fastcgi.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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # deny access to .htaccess files, if Apache&amp;#39;s document root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # concurs with nginx&amp;#39;s one&#10;&lt;/span&gt;&lt;/span&gt;&lt;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 ~ /\.ht {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # deny 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;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&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;sudo vim /etc/php-fpm.d/www.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&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;; List of ipv4 addresses of FastCGI clients which are allowed to connect.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; must be separated by a comma. If this value is left blank, connections will be&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; accepted from any ip address.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Default Value: any&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;listen.allowed_clients = 127.0.0.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen = /tmp/php5-fpm.sock&#10;&lt;/span&gt;&lt;/span&gt;&lt;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 permissions for unix socket, if one is used. In Linux, read/write&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; permissions must be set in order to allow connections from a web server. Many&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; BSD-derived systems allow connections regardless of permissions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Default Values: user and group are set as the running user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; mode is set to 0660&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen.owner = nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen.group = nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen.mode = 0660&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Unix user/group of processes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Note: The user is mandatory. If the group is not set, the default user&amp;#39;s group&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;&#9;will be used.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; RPM: apache Choosed to be able to access some dir as httpd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user = nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; RPM: Keep a group allowed to write in log dir.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;group = nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&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;sudo service php-fpm restart&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /usr/share/nginx/html/info.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&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;重启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;sudo service nginx restart&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试PHP是否正确处理。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/php-fpm.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="php-fpm" class="gallery-image" data-flex-basis="237px" data-flex-grow="99" 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/2015/05/php-fpm-297x300.png" width="297"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.if-not-true-then-false.com/2011/nginx-and-php-fpm-configuration-and-optimizing-tips-and-tricks/" target="_blank" rel="noopener"&#10; &gt;Nginx and PHP-FPM Configuration and Optimizing Tips and Tricks&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zh.wikipedia.org/wiki/Nginx" target="_blank" rel="noopener"&#10; &gt;nginx&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/install.fpm.php" target="_blank" rel="noopener"&#10; &gt;FastCGI 进程管理器（FPM）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.a2o.si/2009/06/24/apache-mod_php-compared-to-nginx-php-fpm/" target="_blank" rel="noopener"&#10; &gt;Apache + mod_php compared to Nginx + php-fpm&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.layershift.com/which-php-mode-apache-vs-cgi-vs-fastcgi/" target="_blank" rel="noopener"&#10; &gt;Which PHP mode? Apache vs CGI vs FastCGI&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://serverfault.com/questions/6733/php-what-are-the-advantages-of-fastcgi-over-mod-php" target="_blank" rel="noopener"&#10; &gt;PHP: What are the advantages of FastCGI over mod_php?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.quora.com/What-are-the-advantages-of-using-PHP-FPM-&amp;#43;-Nginx-over-Apache-and-mod_php" target="_blank" rel="noopener"&#10; &gt;What are the advantages of using PHP-FPM + Nginx over Apache and mod_php?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.howtoforge.com/how-to-install-nginx-with-php5-and-php-fpm-and-mysql-on-centos-6.5-p2" target="_blank" rel="noopener"&#10; &gt;How To Install Nginx With PHP5 (And PHP-FPM) And MySQL Support On CentOS 6.5&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-on-centos-6" target="_blank" rel="noopener"&#10; &gt;How To Install Linux, nginx, MySQL, PHP (LEMP) stack on CentOS 6&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2009/07/28/1030.html" target="_blank" rel="noopener"&#10; &gt;Linux上配置Nginx+PHP5(FastCGI)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2011/04/13/1991.html" target="_blank" rel="noopener"&#10; &gt;使用fastcgi_finish_request提高页面响应速度&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.bo56.com/%E5%96%84%E7%94%A8php-fpm%E7%9A%84%E6%85%A2%E6%89%A7%E8%A1%8C%E6%97%A5%E5%BF%97slow-log%EF%BC%8C%E5%88%86%E6%9E%90php%E6%80%A7%E8%83%BD%E9%97%AE%E9%A2%98/" target="_blank" rel="noopener"&#10; &gt;善用php-fpm的慢执行日志slow log，分析php性能问题&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.guangla.com/post/swoole-reload" target="_blank" rel="noopener"&#10; &gt;swoole之代码热更新实现&lt;/a&gt;&lt;/p&gt;&#10;</description></item></channel></rss>