<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://kenme.org/feed.xml" rel="self" type="application/atom+xml" /><link href="https://kenme.org/" rel="alternate" type="text/html" /><updated>2025-05-12T00:23:04+08:00</updated><id>https://kenme.org/feed.xml</id><title type="html">Han Ke</title><subtitle>Do not go gentle into that good night, Old age should burn and rave at close of day; Rage, rage against the dying of the light.</subtitle><entry><title type="html">Git Cookbook</title><link href="https://kenme.org/2018/04/18/git-cookbook.html" rel="alternate" type="text/html" title="Git Cookbook" /><published>2018-04-18T00:00:00+08:00</published><updated>2018-04-18T00:00:00+08:00</updated><id>https://kenme.org/2018/04/18/git-cookbook</id><content type="html" xml:base="https://kenme.org/2018/04/18/git-cookbook.html"><![CDATA[<h2 id="分支">分支</h2>
<ul>
  <li>查看所有分支
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch -a
</code></pre></div>    </div>
  </li>
  <li>查看所有远程分支
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   git branch -r
</code></pre></div>    </div>
  </li>
  <li>查看所有本地分支
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   git branch 
</code></pre></div>    </div>
  </li>
  <li>查看本地分支与远程分支的追踪关系
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch -vv
</code></pre></div>    </div>
  </li>
  <li>建立本地分支与远程分支的追踪关系
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git branch --set-upstream [本地分支名] [远程主机名]/[远程分支名]
</code></pre></div>    </div>
  </li>
  <li>修改分支名
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git branch -m [分支名] [新分支名]
  # 注1: 分支名可省略， 默认当前分支
</code></pre></div>    </div>
  </li>
  <li>切换分支
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git checkout [分支名]
</code></pre></div>    </div>
  </li>
  <li>建立并切换至分支
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git checkout -b [分支名]
</code></pre></div>    </div>
  </li>
</ul>

<h2 id="远程主机">远程主机</h2>
<ul>
  <li>查看远程主机
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   git remote
   # 查看地址
   git remote -v 
</code></pre></div>    </div>
  </li>
  <li>添加删除远程主机
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git remote add []
</code></pre></div>    </div>
  </li>
  <li>添加远程主机
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git remote rename [主机名] [新分支名]
</code></pre></div>    </div>
  </li>
</ul>

<h2 id="同步远程到本地">同步远程到本地</h2>
<ul>
  <li>同步远程分支到本地
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git fetch [远程主机名] [远程分支]
  # 注：本地分支不会发生任何变化
</code></pre></div>    </div>
  </li>
  <li>合并远程分支到当前本地分支
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git merge [远程主机名]/[远程分支]
</code></pre></div>    </div>
  </li>
  <li>同步远程分支并合并到本地分支
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git pull [远程主机名] [远程分支]:[本地分支]
  # 若已建立远程分支与本地分支的追踪关系, 
  # 可运行下面命令使当前本地分支与远程分支一致
  git pull [远程主机名]
  # 若只有一个主机， 可简化为
  git pull
</code></pre></div>    </div>
    <h2 id="推送本地到远程">推送本地到远程</h2>
  </li>
  <li>推送本地分支到远程分支
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  git push [远程主机名] [本地分支]:[远程分支]
  # 注1：注意与pull命令的区别
  # 注2: 同pull命令相同，也可以在有追踪关系的情况下简化参数
  # 注3: 远程分支不存在时，会自动建立远程分支，并建立追踪关系
  # 注4: push不会同步标签，除非使用 --tags 选项
</code></pre></div>    </div>
  </li>
</ul>]]></content><author><name></name></author><category term="git" /><summary type="html"><![CDATA[分支 查看所有分支 git branch -a 查看所有远程分支 git branch -r 查看所有本地分支 git branch 查看本地分支与远程分支的追踪关系 git branch -vv 建立本地分支与远程分支的追踪关系 git branch --set-upstream [本地分支名] [远程主机名]/[远程分支名] 修改分支名 git branch -m [分支名] [新分支名] # 注1: 分支名可省略， 默认当前分支 切换分支 git checkout [分支名] 建立并切换至分支 git checkout -b [分支名]]]></summary></entry><entry><title type="html">Linux 下常用压缩命令</title><link href="https://kenme.org/2018/04/10/Linux-%E4%B8%8B%E5%B8%B8%E7%94%A8%E5%8E%8B%E7%BC%A9%E5%91%BD%E4%BB%A4.html" rel="alternate" type="text/html" title="Linux 下常用压缩命令" /><published>2018-04-10T00:00:00+08:00</published><updated>2018-04-10T00:00:00+08:00</updated><id>https://kenme.org/2018/04/10/Linux%20%E4%B8%8B%E5%B8%B8%E7%94%A8%E5%8E%8B%E7%BC%A9%E5%91%BD%E4%BB%A4</id><content type="html" xml:base="https://kenme.org/2018/04/10/Linux-%E4%B8%8B%E5%B8%B8%E7%94%A8%E5%8E%8B%E7%BC%A9%E5%91%BD%E4%BB%A4.html"><![CDATA[<p>Linux 下常用的压缩打包软件是tar命令，本文也就解释一下tar命令的使用方法，列出常用的tar命令。</p>

<h2 id="tar-命令详解">Tar 命令详解</h2>

<p>可以使用<code class="language-plaintext highlighter-rouge">man tar</code>来查看详情，这里给出主要的参数</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tar</span> <span class="o">[</span>选项] <span class="o">[</span>参数]

选项：
    <span class="nt">-A</span>或--catenate：新增文件到以存在的备份文件；
    <span class="nt">-B</span>：设置区块大小；
    <span class="nt">-c</span>或--create：建立新的备份文件；
    <span class="nt">-C</span> &lt;目录&gt;：这个选项用在解压缩，若要在特定目录解压缩，可以使用这个选项。
    <span class="nt">-d</span>：记录文件的差别；
    <span class="nt">-x</span>或--extract或--get：从备份文件中还原文件；
    <span class="nt">-t</span>或--list：列出备份文件的内容；
    <span class="nt">-z</span>或--gzip或--ungzip：通过gzip指令处理备份文件；
    <span class="nt">-Z</span>或--compress或--uncompress：通过compress指令处理备份文件；
    <span class="nt">-f</span>&lt;备份文件&gt;或--file<span class="o">=</span>&lt;备份文件&gt;：指定备份文件；
    <span class="nt">-v</span>或--verbose：显示指令执行过程；
    <span class="nt">-r</span>：添加文件到已经压缩的文件；
    <span class="nt">-u</span>：添加改变了和现有的文件到已经存在的压缩文件；
    <span class="nt">-j</span>：支持bzip2解压文件；
    <span class="nt">-v</span>：显示操作过程；
    <span class="nt">-l</span>：文件系统边界设置；
    <span class="nt">-k</span>：保留原有文件不覆盖；
    <span class="nt">-m</span>：保留文件不被覆盖；
    <span class="nt">-w</span>：确认压缩文件的正确性；
    <span class="nt">-p</span>或--same-permissions：用原来的文件权限还原文件；
    <span class="nt">-P</span>或--absolute-names：文件名使用绝对名称，不移除文件名称前的“/”号；
    <span class="nt">-N</span> &lt;日期格式&gt; 或 <span class="nt">--newer</span><span class="o">=</span>&lt;日期时间&gt;：只将较指定日期更新的文件保存到备份文件里；
    <span class="nt">--exclude</span><span class="o">=</span>&lt;范本样式&gt;：排除符合范本样式的文件。
</code></pre></div></div>

<h2 id="实例">实例</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">tar -czf [文件名].tar.gz [路径]</code> 以gzip压缩算法压缩文件</li>
  <li><code class="language-plaintext highlighter-rouge">tar -cjf [文件名].tar.xz [路径]</code> 以bzip2压缩算法压缩文件</li>
  <li>`tar -</li>
</ul>]]></content><author><name></name></author><category term="shell" /><summary type="html"><![CDATA[Linux 下常用的压缩打包软件是tar命令，本文也就解释一下tar命令的使用方法，列出常用的tar命令。]]></summary></entry><entry><title type="html">Python类的属性检查</title><link href="https://kenme.org/2017/09/08/%E7%B1%BB%E7%9A%84%E5%B1%9E%E6%80%A7%E6%A3%80%E6%9F%A5.html" rel="alternate" type="text/html" title="Python类的属性检查" /><published>2017-09-08T00:00:00+08:00</published><updated>2017-09-08T00:00:00+08:00</updated><id>https://kenme.org/2017/09/08/%E7%B1%BB%E7%9A%84%E5%B1%9E%E6%80%A7%E6%A3%80%E6%9F%A5</id><content type="html" xml:base="https://kenme.org/2017/09/08/%E7%B1%BB%E7%9A%84%E5%B1%9E%E6%80%A7%E6%A3%80%E6%9F%A5.html"><![CDATA[<p>在绑定属性时，如果我们直接把属性暴露出去，虽然写起来很简单，但是，没办法检查参数，导致属性可以把随便更改：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Foo(object):
	pass

foo1 = Foo()
foo1.age = 666
</code></pre></div></div>

<p>这显然不合逻辑。为了限制age的范围，可以通过一个<code class="language-plaintext highlighter-rouge">set_age()</code>方法来设置成绩，再通过一个<code class="language-plaintext highlighter-rouge">get_age()</code>来获取成绩，这样，在<code class="language-plaintext highlighter-rouge">set_age()</code>方法里，就可以检查参数：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Foo(object):
	
    def get_age(self):
         return self._age

    def set_age(self, value):
        if not isinstance(value, int):
            raise ValueError('age must be an integer!')
        if value &lt; 0 or value &gt; 130:
            raise ValueError('age must between 0 ~ 130!')
        self._age = value
</code></pre></div></div>

<p>现在，对任意的Foo实例进行操作，就不能随心所欲地设置age了：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; foo2 = Foo()
&gt;&gt;&gt; foo2.set_age(60) # ok!
&gt;&gt;&gt; foo2.get_age()
60
&gt;&gt;&gt; foo2.set_age(9999)
Traceback (most recent call last):
  ...
ValueError: age must between 0 ~ 130!
</code></pre></div></div>

<p>但是，上面的调用方法又略显复杂，没有直接用属性这么直接简单。</p>

<p>有没有既能检查参数，又可以用类似属性这样简单的方式来访问类的变量呢？</p>

<p>Python装饰器（decorator）可以给函数动态加上功能对于类的方法，装饰器一样起作用。Python内置的<code class="language-plaintext highlighter-rouge">@property</code>装饰器就是负责把一个方法变成属性调用的：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Foo(object):

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if not isinstance(value, int):
            raise ValueError('age must be an integer!')
        if value &lt; 0 or value &gt; 130:
            raise ValueError('age must between 0 ~ 130!')
        self._age = value
</code></pre></div></div>

<p>把一个getter方法变成属性，只需要加上<code class="language-plaintext highlighter-rouge">@property</code>就可以了，此时，<code class="language-plaintext highlighter-rouge">@property</code>本身又创建了另一个装饰器<code class="language-plaintext highlighter-rouge">@age.setter</code>，负责把一个setter方法变成属性赋值，于是，我们就拥有一个可控的属性操作：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; foo3 = Foo()
&gt;&gt;&gt; foo3.age = 60 # OK，实际转化为age.set_score(60)
&gt;&gt;&gt; foo3.age # OK，实际转化为age.get_score()
60
&gt;&gt;&gt; foo3.age = 9999
Traceback (most recent call last):
  ...
ValueError: age must between 0 ~ 130!
</code></pre></div></div>

<p>注意到这个神奇的<code class="language-plaintext highlighter-rouge">@property</code>，我们在对实例属性操作的时候，就知道该属性很可能不是直接暴露的，而是通过getter和setter方法来实现的。</p>

<p>还可以定义只读属性，只定义getter方法，不定义setter方法就是一个只读属性：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Foo(object):

    @property
    def birth(self):
        return self._birth

    @birth.setter
    def birth(self, value):
        self._birth = value

    @property
    def age(self):
        return 2017 - self._birth
</code></pre></div></div>

<p>上面的<code class="language-plaintext highlighter-rouge">birth</code>是可读写属性，而<code class="language-plaintext highlighter-rouge">age</code>就是一个<strong>只读</strong>属性，因为<code class="language-plaintext highlighter-rouge">age</code>可以根据<code class="language-plaintext highlighter-rouge">birth</code>和当前时间计算出来。</p>

<h3 id="小结">小结</h3>

<p><code class="language-plaintext highlighter-rouge">@property</code>广泛应用在类的定义中，可以让调用者写出简短的代码，同时保证对参数进行必要的检查，这样，程序运行时就减少了出错的可能性。</p>]]></content><author><name></name></author><category term="python" /><summary type="html"><![CDATA[在绑定属性时，如果我们直接把属性暴露出去，虽然写起来很简单，但是，没办法检查参数，导致属性可以把随便更改：]]></summary></entry><entry><title type="html">Markdown Tutorals</title><link href="https://kenme.org/2017/07/22/markdown-tutorals.html" rel="alternate" type="text/html" title="Markdown Tutorals" /><published>2017-07-22T00:00:00+08:00</published><updated>2017-07-22T00:00:00+08:00</updated><id>https://kenme.org/2017/07/22/markdown-tutorals</id><content type="html" xml:base="https://kenme.org/2017/07/22/markdown-tutorals.html"><![CDATA[<h3 id="markdown介绍">Markdown介绍：</h3>

<p><a href="https://zh.wikipedia.org/wiki/Markdown" title="维基百科">Markdown</a> 是一种轻量级标记语言，创始人为约翰·格鲁伯（John Gruber）。它允许人们“使用易读易写的纯文本格式编写文档，然后转换成有效的XHTML(或者HTML)文档”。这种语言吸收了很多在电子邮件中已有的纯文本标记的特性。John Gruber 在 2004 年创造了 Markdown 语言，在语法上有很大一部分是跟亚伦·斯沃茨（Aaron Swartz）共同合作的。这个语言的目的是希望大家使用“易于阅读、易于撰写的纯文字格式，并选择性的转换成有效的 XHTML (或是HTML)”。 其中最重要的设计是可读性，也就是说这个语言应该要能直接在字面上的被阅读，而不用被一些格式化指令标记 (像是 RTF 与 HTML)。 因此，它是现行电子邮件标记格式的惯例，虽然它也借鉴了很多早期的标记语言，如：setext、Texile、reStructuredText。 许多网站都使用Markdown 或是其变种，例如：GitHub、reddit、Diaspora、Stack Exchange、OpenStreetMap 与 SourceForge 让用户更利于讨论。</p>

<h3 id="markdown编辑器">Markdown编辑器</h3>

<p>推荐<a href="https://www.typora.io/" title="Typora — a minimal markdown reading &amp; writing app">Typora</a>，支持Windows，Linux，MacOS。即时显示，设计精美，体验非常好。</p>

<p><img src="https://public.lightpic.info/image/DB8E_5901B2031.gif" alt="Typora演示" /></p>

<h3 id="markdown语法">Markdown语法：</h3>

<p>推荐简书的<a href="http://www.jianshu.com/p/q81RER">献给写作者的 Markdown 新手指南</a>，重要语法收录如下</p>

<h4 id="标题">标题</h4>

<blockquote>
  <p>这是最为常用的格式，在平时常用的的文本编辑器中大多是这样实现的：输入文本、选中文本、设置标题格式。</p>

  <p>而在 Markdown 中，你只需要在文本前面加上 <code class="language-plaintext highlighter-rouge">#</code> 即可，同理、你还可以增加二级标题、三级标题、四级标题、五级标题和六级标题，总共六级，只需要增加 <code class="language-plaintext highlighter-rouge">#</code> 即可，标题字号相应降低。例如：</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
</code></pre></div>  </div>

  <p><em>注：# 和「一级标题」之间建议保留一个字符的空格，这是最标准的 Markdown 写法。</em></p>
</blockquote>

<h4 id="列表">列表</h4>

<blockquote>
  <p>列表格式也很常用，在 Markdown 中，你只需要在文字前面加上 <code class="language-plaintext highlighter-rouge">-</code> 就可以了，例如：</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- 文本1
- 文本2
- 文本3
</code></pre></div>  </div>

  <p>如果你希望有序列表，
也可以在文字前面加上 <code class="language-plaintext highlighter-rouge">1.</code> <code class="language-plaintext highlighter-rouge">2.</code> <code class="language-plaintext highlighter-rouge">3.</code> 就可以了，例如：</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. 文本1
2. 文本2
3. 文本3
</code></pre></div>  </div>

  <p><em>注：-、1.和文本之间要保留一个字符的空格。</em></p>
</blockquote>

<h4 id="链接和图片">链接和图片</h4>

<blockquote>
  <p>在 Markdown 中，插入链接不需要其他按钮，你只需要使用 <code class="language-plaintext highlighter-rouge">[显示文本](链接地址)</code> 这样的语法即可，例如：</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[简书](http://www.jianshu.com)
</code></pre></div>  </div>

  <p>在 Markdown 中，插入图片不需要其他按钮，你只需要使用 <code class="language-plaintext highlighter-rouge">![](图片链接地址)</code> 这样的语法即可，例如：</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>![](http://upload-images.jianshu.io/upload_images/259-0ad0d0bfc1c608b6.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
</code></pre></div>  </div>

  <p><em>注：插入图片的语法和链接的语法很像，只是前面多了一个 ！。</em></p>
</blockquote>

<h4 id="引用">引用</h4>

<blockquote>
  <p>在我们写作的时候经常需要引用他人的文字，这个时候引用这个格式就很有必要了，在 Markdown 中，你只需要在你希望引用的文字前面加上 <code class="language-plaintext highlighter-rouge">&gt;</code> 就好了，例如：</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; 一盏灯， 一片昏黄； 一简书， 一杯淡茶。 守着那一份淡定， 品读属于自己的寂寞。 保持淡定， 才能欣赏到最美丽的风景！ 保持淡定， 人生从此不再寂寞。
</code></pre></div>  </div>

  <p><em>注：&gt; 和文本之间要保留一个字符的空格。</em></p>
</blockquote>

<h4 id="粗体和斜体">粗体和斜体</h4>

<blockquote>
  <p>Markdown 的粗体和斜体也非常简单，用两个 <code class="language-plaintext highlighter-rouge">*</code> 包含一段文本就是粗体的语法，用一个 <code class="language-plaintext highlighter-rouge">*</code> 包含一段文本就是斜体的语法。例如：</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> *一盏灯*， 一片昏黄；**一简书**， 一杯淡茶。 守着那一份淡定， 品读属于自己的寂寞。 保持淡定， 才能欣赏到最美丽的风景！ 保持淡定， 人生从此不再寂寞。
</code></pre></div>  </div>

  <p>最终显示的就是下文，其中「一盏灯」是斜体，「一简书」是粗体：</p>

  <p><em>一盏灯</em>， 一片昏黄；<strong>一简书</strong>， 一杯淡茶。 守着那一份淡定， 品读属于自己的寂寞。 保持淡定， 才能欣赏到最美丽的风景！ 保持淡定， 人生从此不再寂寞。</p>
</blockquote>

<h4 id="代码引用">代码引用</h4>

<blockquote>
  <p>需要引用代码时，如果引用的语句只有一段，不分行，可以用 ` 将语句包起来。</p>

  <p>如果引用的语句为多行，可以将```置于这段代码的首行和末行。</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>`单行代码代码`
​```
多行代码
​```
</code></pre></div>  </div>

  <p>最终显示的就是下文：</p>

  <p><code class="language-plaintext highlighter-rouge">单行代码</code></p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>多行代码
</code></pre></div>  </div>
</blockquote>

<h4 id="表格">表格</h4>

<blockquote>
  <p>相关代码：</p>

  <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| Tables        | Are           | Cool  |
| ------------- |:-------------:| -----:|
| col 3 is      | right-aligned | $1600 |
| col 2 is      | centered      |   $12 |
| zebra stripes | are neat      |    $1 |
</code></pre></div>  </div>

  <p>显示效果：</p>

  <table>
    <thead>
      <tr>
        <th style="text-align: left">Tables</th>
        <th style="text-align: center">Are</th>
        <th style="text-align: right">Cool</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td style="text-align: left">col 3 is</td>
        <td style="text-align: center">right-aligned</td>
        <td style="text-align: right">$1600</td>
      </tr>
      <tr>
        <td style="text-align: left">col 2 is</td>
        <td style="text-align: center">centered</td>
        <td style="text-align: right">$12</td>
      </tr>
      <tr>
        <td style="text-align: left">zebra stripes</td>
        <td style="text-align: center">are neat</td>
        <td style="text-align: right">$1</td>
      </tr>
    </tbody>
  </table>
</blockquote>]]></content><author><name></name></author><category term="markdown" /><summary type="html"><![CDATA[Markdown介绍：]]></summary></entry><entry><title type="html">Nginx uWSGI Flask 部署</title><link href="https://kenme.org/2017/05/22/nginx-uwsgi-flask-deploy.html" rel="alternate" type="text/html" title="Nginx uWSGI Flask 部署" /><published>2017-05-22T00:00:00+08:00</published><updated>2017-05-22T00:00:00+08:00</updated><id>https://kenme.org/2017/05/22/nginx-uwsgi-flask-deploy</id><content type="html" xml:base="https://kenme.org/2017/05/22/nginx-uwsgi-flask-deploy.html"><![CDATA[<p>本人最近在<a href="https://bandwagonhost.com/" title="bandwagonhost">搬瓦工</a>上部署了自己的Django博客，把自己踩的坑先记录下来，防止下次继续踩坑。主要参考uWSGI的<a href="http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html" title="Setting up Django and your web server with uWSGI and nginx">官方文档</a>。以下代码中，”（）“内带中文的要修改为自己的，”#“ 后面的内容是注释。</p>

<h2 id="1-基础环境配置">1. 基础环境配置</h2>

<p>先安装好基础环境</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
sudo yum groupinstall "Development tools"
sudo yum install python34 python34-devel python34-pip
pip3 install virtualenv
virtualenv python34
source python34/bin/activate

</code></pre></div></div>

<p>测试python环境</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python --version
pip --version
</code></pre></div></div>

<p>如果是python3.4的环境，至此python环境配置好了，如果有错，多用一下Google解决。</p>

<h2 id="2-nginx安装">2. Nginx安装</h2>

<p>参考Nginx官网的<a href="https://nginx.org/en/linux_packages.html" title="Nginx安装文档">安装文档</a>，建议新手使用yum安装，后续升级维护方便。</p>

<ol>
  <li>首先要安装Nginx仓库，<code class="language-plaintext highlighter-rouge">sudo vi /etc/yum.repos.d/nginx.repo</code>添加以下内容：</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=1
enabled=1
</code></pre></div></div>

<ol>
  <li>下载Nginx的key文件，<code class="language-plaintext highlighter-rouge">wget https://nginx.org/keys/nginx_signing.key</code></li>
  <li>安装key文件，<code class="language-plaintext highlighter-rouge">sudo rpm --import nginx_signing.key</code></li>
  <li>安装Nginx，<code class="language-plaintext highlighter-rouge">sudo yum install nginx</code></li>
  <li>测试Nginx，<code class="language-plaintext highlighter-rouge">sudo nginx</code></li>
</ol>

<h2 id="3-uwsgi安装">3. uWSGI安装</h2>

<p>从此往下都需要在Python34的虚拟环境下，检查自己是否在Python34虚拟环境下，不在的话执行<code class="language-plaintext highlighter-rouge">source python34/bin/activate</code>确认进入虚拟环境，执行<code class="language-plaintext highlighter-rouge">pip install uwsgi	</code>安装uWSGI，测试uWSGI是否安装好。执行<code class="language-plaintext highlighter-rouge">vi test.py</code>输入一下内容保存：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"]
</code></pre></div></div>

<p>开启uWSGI服务，<code class="language-plaintext highlighter-rouge">uwsgi --http :8000 --wsgi-file test.py</code>，打开浏览器，输入<code class="language-plaintext highlighter-rouge">(你的IP):8000</code>看到<code class="language-plaintext highlighter-rouge">Hello World</code>代表web client到uWSGI到Python的连接正常。</p>

<h2 id="4-django配置">4. Django配置</h2>

<p>先执行<code class="language-plaintext highlighter-rouge">pip install -r requirements.txt</code>安装好Python包，正式部署前要配置好Django项目的配置(settings.py)，修改一下项目：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1','localhost','(你的域名)']
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
</code></pre></div></div>

<p>然后记得执行一下语句:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser # 创建超级用户
python manage.py collectstatic
</code></pre></div></div>

<p>然后执行<code class="language-plaintext highlighter-rouge">python manage.py runserver</code>测试Django项目运行是否正常。</p>

<h2 id="5-uwsgi到django配置">5. uWSGI到Django配置</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>uwsgi --http :8000 --module （你的Djnago项目名）.wsgi
</code></pre></div></div>

<p>打开浏览器测试（8000端口），如果Django项目运行正常，表示Web Client到uWSGI到Django运行正常。</p>

<p><code class="language-plaintext highlighter-rouge">vi uwsgi.ini</code>添加以下内容并保存</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[uwsgi]
socket = :8001
chdir= (你的Django项目地址)
wsgi-file = (你的Django项目地址下wsgi.py所在位置)
touch-reload = ~/reload # 如果reload文件有更改，重启uWSGI
module=(你的Django项目名称).wsgi
master=true
processes = 2 # 进程数
threads = 4 # 线程数
chmod-socket    = 664
chown-socket = （centos用户名）:（centos组）
vacuum=true
pidfile = ~/tmp/uwsgi.pid #pid 文件位置 
</code></pre></div></div>

<p>执行<code class="language-plaintext highlighter-rouge">uWSGI --ini uwsgi.ini  &amp;</code>运行uWSGI，如果Django项目有更改的话可以执行<code class="language-plaintext highlighter-rouge">touch ~/reload</code>重启uWSGI。</p>

<h2 id="6-配置nginx">6. 配置Nginx</h2>

<p>执行 <code class="language-plaintext highlighter-rouge">sudo vi /etc/nginx/nginx.conf</code>修改添加一下内容</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># 注意，这只是nginx.conf中的一部分，其他内容不熟悉的话不要修改。

http {
    upstream django {
        server 127.0.0.1:8001;
    }

    server {
        listen       80;
        server_name  （你的域名地址）;
        if ($host != 'www.willtunner.me' ) {
            rewrite ^/(.*)$ http://www.willtunner.me/$1 permanent;
        }   # 此处修改自动添加www

        charset utf-8;
        access_log  logs/host.access.log  main;

        location / {
            uwsgi_pass  django;
            include     /etc/nginx/uwsgi_params;
        }

        location /static/ {
            alias （你的Django项目static地址）;
        }

        location /media/ {
            alias （你的Django项目media地址）;
        }

        location ~ .*.txt$ {
            root （robots.txt所在地址）;
        }
    }
}
</code></pre></div></div>

<p>当然Nginx虚拟主机配置最好使用include语法放置在其他文件夹下，多个虚拟主机比较好管理，这里我只有一个虚拟主机，故直接在这里修改了。</p>

<p>改好了之后执行<code class="language-plaintext highlighter-rouge">sudo nginx -s stop</code>和<code class="language-plaintext highlighter-rouge">sudo nginx</code>重新加载Nginx的配置。</p>

<p>没有出错的话，至此从Web Client到Nginx到uWSGi到Django的通路便建立好了。网站可以正常访问了。</p>]]></content><author><name></name></author><category term="nginx" /><category term="flask" /><category term="python" /><category term="uwsgi" /><summary type="html"><![CDATA[本人最近在搬瓦工上部署了自己的Django博客，把自己踩的坑先记录下来，防止下次继续踩坑。主要参考uWSGI的官方文档。以下代码中，”（）“内带中文的要修改为自己的，”#“ 后面的内容是注释。]]></summary></entry></feed>