Ubuntu 12.04でpyenvを利用して速攻でPython3.4 + Nginx + uWSGI + FlaskなWebアプリケーション実行環境を作る


# 登場人物

- ぼく  
  去年まで女子校だった私立高校に通う普通の高校生。人間が嫌い。これ以降登場しない。
- Ubuntu  
  Linuxらしいが、よく知らない。
- pyenv  
  Pythonのバージョンを切り替えるやつ。virtualenvとの連携で使い勝手が超いいらしいが、よく知らない。
- Nginx  
  Webサーバーらしいが、よく知らない。
- uWSGI  
  WSGIサーバーらしいが、何のことか分からない。そもそもWSGIを知らない。
- Flask  
  Webアプリケーションを気軽に作れる軽量のフレームワークらしいが、よく知らない。

# pyenvの設定とPythonのインストール

システムのPythonには指一本触れません。
更にpyenvでインストールしたPythonに対しても直接いじることはしません。
パッケージのインストールなどはすべてvirtualenvを使います。
また、普通はpyenvのディレクトリは`$HOME`以下に作ることが多いと思いますが、
システムから利用するのが`$HOME`以下にあるのがイマイチ落ち着かないので、ここでは`/opt`以下に用意します。
なので、pyenv絡みの作業はrootで行うことが多くなります。

とりあえずgitが要ります。

```bash
$ sudo apt-get install git
```

## Pythonのビルドのためのパッケージインストール

Pythonのビルドには以下のパッケージが要るのでインストールしておく。

Cコンパイラなど

```bash
$ sudo apt-get install build-essential
```

SQLiteサポートのためのSQLiteライブラリなど

```bash
$ sudo apt-get install libsqlite3-dev
$ sudo apt-get install sqlite3
$ sudo apt-get install bzip2 libbz2-dev
```

pipが必要とするSSLライブラリ

```bash
$ sudo apt-get install libssl-dev openssl
```
readline拡張が必要とするreadlineライブラリ

```bash
$ sudo apt-get install libreadline6 libreadline6-dev
```

## pyenv本体とpyenv-virtualenvプラグインのインストール

rootでやります。

```bash
sudo su
cd /opt
git clone git://github.com/yyuu/pyenv.git pyenv

echo 'export PYENV_ROOT="/opt/pyenv"' >> ~/.bashrc
echo 'if [ -d "${PYENV_ROOT}" ]; then' >> ~/.bashrc
echo '    export PATH=${PYENV_ROOT}/bin:$PATH' >> ~/.bashrc
echo '    eval "$(pyenv init -)"' >> ~/.bashrc
echo 'fi' >> ~/.bashrc

exec $SHELL -l

cd $PYENV_ROOT/plugins
git clone git://github.com/yyuu/pyenv-virtualenv.git
```

## Python 3.4.0 のインストール

```bash
sudo su
pyenv install 3.4.0
```

## pyenvの簡単な使い方

メモ的に。

- インストール可能なバージョンのリストを表示  
  
  ```bash
  pyenv install --list
  ```

- 3.4.0をインストール  

  ```bash
  pyenv install 3.4.0
  ```

- インストール済みバージョンのリスト  
  
  ```bash
  pyenv versions
  ```

- virtualenv環境の作成  
  
  ```bash
  pyenv virtualenv 3.4.0 my-virtual-env-3.4.0
  ```

- virtualenv環境のリスト  
  
  ```bash
  pyenv virtualenvs
  ```

- virtualenvの有効化  
  
  ```bash
  pyenv activate my-virtual-env-3.4.0
  ```

- インストールした環境の削除  
  
  ```bash
  pyenv uninstall my-virtual-env-3.4.0
```

# Nginxのインストール

`add-apt-repository`コマンドを利用するため、`python-software-properties`パッケージをインストール

```bash
sudo apt-get install python-software-properties
```

Nginxのstableリポジトリを追加

```bash
$ sudo add-apt-repository ppa:nginx/stable
```

いつものupdate/upgrade

```bash
sudo apt-get update
sudo apt-get upgrade
```

Nginxのインストールと起動

```bash
sudo apt-get install nginx
sudo /etc/init.d/nginx start
```

ブラウザで接続し、Nginxのgreetingsページが表示されることを確認する。

# flaskサンプルアプリケーションの構築

## アプリケーションのディレクトリを作成

アプリケーションのディレクトリを作成。
アプリケーションの関連ファイルは全てここに格納する。
_※ただし、virtualenv環境は/opt以下などでpyenvに一括管理させる。_

```bash
sudo mkdir -p /var/www/demoapp
```

ユーザー権限がrootのままだとあれなので、自分の利用しているユーザーに変更しておく

```bash
sudo chown -R username:username /var/www/demoapp/
```

## サンプルアプリケーション用のvirtualenvの作成

```bash
sudo -s
pyenv virtualenv 3.4.0 demoapp
```

## Flaskのインストール

virtualenvにFlaskのインストール

```bash
sudo -s
pyenv activate demoapp
pip install flask
```

## Flaskアプリケーションの作成

`/var/www/demoapp/hello.py`を作成。

```python
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8080)
```

## flaskアプリケーションの起動テスト

```bash
pyenv activate demoapp
python /var/www/demoapp/hello.py
```

webブラウザでサーバーのポート:8080に接続し確認。

# uWSGIのインストール

## uWSGI用のvirtualenv環境の構築

uWSGIは複数アプリケーションで共用すると思うので、
アプリケーション用のvirtualenvとはまた別に用意する。

アプリケーション用の `demoapp` virtualenvを有効化していたらdeactivate.

```bash
deactivate
```
uWSGI用のvirtualenv


```bash
sudo -s
pyenv virtualenv 3.4.0 uwsgi-3.4.0
```

## uWSGIのインストール

```bash
sudo -s
pyenv activate uwsgi-3.4.0
pip install uwsgi
```

# Nginxの設定

デフォルトのサイト設定を削除

```bash
sudo rm /etc/nginx/sites-enabled/default
```

サンプルアプリケーション用の設定ファイルを作成

`/var/www/demoapp/demoapp_nginx.conf` を作成

```
server {
    listen      80;
    server_name localhost;
    charset     utf-8;
    client_max_body_size 75M;

    location / { try_files $uri @yourapplication; }
    location @yourapplication {
        include uwsgi_params;
        uwsgi_pass unix:/var/www/demoapp/demoapp_uwsgi.sock;
    }
}
```

Nginxの設定ファイルのディレクトリにシンボリックリンクを貼る

```bash
sudo ln -s /var/www/demoapp/demoapp_nginx.conf /etc/nginx/conf.d/
```

Nginxの再起動

```bash
sudo /etc/init.d/nginx restart
```

webブラウザでサーバーに接続し確認。
**この時点では"502 Bad Gateway"のエラーが出るはず。**

# uWSGIの設定

## アプリケーションのuWSGI設定ファイルを作成する

`/var/www/demoapp/demoapp_uwsgi.ini` を作成

```
[uwsgi]
#application's base folder
base = /var/www/demoapp

#python module to import
app = hello
module = %(app)

#virtualenv folder
home = /opt/pyenv/versions/demoapp

pythonpath = %(base)

#socket file's location
socket = /var/www/demoapp/%n.sock

#permissions for the socket file
chmod-socket    = 666

#the variable that holds a flask application inside the module imported at line #6
callable = app

#location of log files
logto = /var/log/uwsgi/%n.log
```

## ログ出力先ディレクトリの作成

```bash
sudo mkdir -p /var/log/uwsgi
sudo chown -R username:username /var/log/uwsgi
```

## uWSGIの起動

```bash
pyenv activate uwsgi-3.4.0
uwsgi --ini /var/www/demoapp/demoapp_uwsgi.ini
```

webブラウザでサーバーに接続し確認。
NginxとuWSGIが問題なくソケット通信できていれば、`Hello World!`が表示される。

# uWSGI Emperor

uWSGI EmperorはuWSGIの設定ファイルを読み込んでuWSGIプロセスを起動する機能。
複数の設定を読み込みプロセス起動を一括管理することができる。

## Upstartファイルの作成

`/etc/init/uwsgi.conf` を作成

```bash
description "uWSGI"
start on runlevel [2345]
stop on runlevel [06]
respawn

env UWSGI=/opt/pyenv/versions/uwsgi-3.4.0/bin/uwsgi
env LOGTO=/var/log/uwsgi/emperor.log

exec $UWSGI --master --emperor /etc/uwsgi/vassals --die-on-term --uid www-data --gid www-data --logto $LOGTO
```

上記の最後の行は、`/etc/uwsgi/vassals`に存在する設定ファイルを探しuWSGIデーモンを起動することを意味しているので、
サンプルアプリケーションのuWSGI設置ファイルへのシンボリックリンクを`/etc/uwsgi/vassals`に作成。

```bash
sudo mkdir -p /etc/uwsgi/vassals
sudo ln -s /var/www/demoapp/demoapp_uwsgi.ini /etc/uwsgi/vassals
```

## 権限の設定

uWSGIデーモンを`www-data`ユーザーで起動する設定としている。
したがって、アプリケーションとログのディレクトリのオーナーを`www-data`にしておく。

```bash
sudo chown -R www-data:www-data /var/www/demoapp/
sudo chown -R www-data:www-data /var/log/uwsgi/
```

NginxとuWSGIが同一の`www-data`ユーザーで動作するため、ソケットのパーミッションを644に変更しておく。

`/var/www/demoapp/demoapp_uwsgi.ini` を編集

```
...
#permissions for the socket file
chmod-socket = 644
```

## uWSGIの起動

```bash
sudo start uwsgi
```

webブラウザでサーバーに接続し確認。
ここまですべて問題なければ、`Hello World!`が表示される。

# 終わりに

一応これでFlaskアプリケーションを動かせるところまではできました。
注意点というか突っ込みどころは色々あるかと思います。
特にNginxとuWSGIの周りは、それぞれのドキュメントやググって設定を詰めてください。

## 参考
http://vladikk.com/2013/09/12/serving-flask-with-nginx-on-ubuntu/