Flask + uWSGI + Nginx でハローワールドするまで @ さくらのVPS (CentOS 6.6)


## 前提
Flaskアプリケーションのローカル環境での開発方法は知っていて、本番環境でのdeploymentの方法が知りたい。uWSGIやNginxについてはあまり知らない。

## 概略
[Flaskの公式](http://flask.pocoo.org/docs/0.10/deploying/)によると

> You can use the builtin server during development, but you should use a full deployment option for production applications. 

とのことなので、アプリを公開するには組み込みサーバーの利用はせずに、別の方法を考える必要があるらしい。様々な方法があるようだが、ここではuWSGIとNginxという組合せで進める。

まず、基本的な言葉の整理からおこなう。

### uWSGI
uWSGIは、WSGIと名前は似ているが異なる概念であることに注意する。

WSGI(Web Server Gateway Interface)は[PEP333](https://www.python.org/dev/peps/pep-0333/)において

> a simple and universal interface between web servers and web applications or frameworks

と定義される仕様のことであり、ウェブサーバとアプリケーションをつなぐインターフェースの役割を担う。これにより、フレームワークとサーバの実装が一般化され、アプリケーションの移植可能性が高まるなどのメリットがある。

uWSGIは、WSGIアプリケーションとウェブサーバをつなぐサーバを指す。uWSGIは、uWSGI、HTTP、そしてFastCGIなどのプロトコルを用いてウェブサーバと通信する。ここでは[uwsgi](http://projects.unbit.it/uwsgi/)というサーバを利用して、uWSGIプロトコルによりウェブサーバと通信する(言葉が紛らわしいですが、uWSGIは文脈によってサーバを指したりプロトコルを指したりするので注意が必要です)。

以上の関係を図式的に表すと次のようになる。

```
Framework <-> uWSGI <-> Web Server <-> Client
```

今回の場合では

```
Flask <-> uwsgi <-(uWSGI protocol)-> Nginx <-(HTTP)-> Client
```

となる。


## インストール

flaskとuwsgiをpipで入れておく。ここは情報が豊富なので省略。


## デモアプリの作成

### アプリの構成

```
myapp
 |-app.py
 |-myapp.ini
 |-venv
```

### app.py

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

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

if __name__ == "__main__":
    app.run()
```

### myapp.ini
これについては後述する。

```ini
[uwsgi]
module = app
callable = app
master = true
processes = 1
socket = /tmp/uwsgi.sock
chmod-socket = 666
vacuum = true
die-on-term = true
```

## Nginxの設定
Nginxの設定ファイルは、大本の設定ファイルは```/etc/nginx/nginx.conf```であり、このファイルの中に```include /etc/nginx/conf.d/*.conf```と記述してあることで、さらに下位の```/etc/nginx/conf.d/```内にある```*.conf```ファイルが呼び出される仕組みとなっている。ここでは、アプリケーションを動かすのに必要な最小限の設定ファイルを```conf.d/```内に置くこととする。

```nginx
server {
    listen       80;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:///tmp/uwsgi.sock;
    }
}
```

これは、サーバのルートにHTTP(ポート80)でアクセスがあれば、```/tmp/uwsgi.sock```というソケットに接続するという設定になっている。上述したように、NginxはuWSGIに接続するのだが、ここではUNIXソケットを間に噛ませて通信する。これにより、ポート番号を消費せずに済む。

このことを加味した全体の接続イメージは次のようになる。

```
Flask <-> uwsgi <-> socket <-> Nginx <-> Client
```

## uWSGIの設定
ここまでで```app.py```を任意の場所に設置してNginxの設定を済ませていれば、次のコマンドで一応アクセスすることができる。

```
$ uwsgi --socket /tmp/uwsgi.sock --module app --callable app --chmod-socket=666
```

あるいは

```
$ uwsgi -s /tmp/uwsgi.sock --w app:app --chmod-socket=666
```

ブラウザからウェブサーバのIPアドレスにアクセスすると、ハローワールドが表示されるはず。上のコマンドの各オプションは次のような意味をもつ。

```
-s|--socket   接続先のソケットの指定
--module   モジュールの指定
--callable    WSGIにて規定されるcallableオブジェクトの指定
--chmod-socket   ソケットのアクセス権の変更
```

しかし、上のオプションを毎度打ち込むのも大変なので、uwsgiのための設定ファイルを作成する。それが上述した```myapp.ini```となる。設定ファイルを作成していれば、次のコマンドで同様にuWSGIサーバーが立ち上がる。

```
$ uwsgi --ini myapp.ini
```

## おわりに
ここまでで、一応FlaskアプリケーションをNginx経由で動かすことはできた。あとは、起動時に自動実行されるよう設定するなどすればOKだろう(そのためには```/etc/rc.local```をいじればいい)。

## 参照
* [Web Server Gateway Interface - Wikipedia](https://ja.wikipedia.org/wiki/Web_Server_Gateway_Interface)
* [PEP 0333 -- Python Web Server Gateway Interface v1.0 | Python.org](https://www.python.org/dev/peps/pep-0333/)
* [uWSGI — Flask Documentation (0.10)](http://flask.pocoo.org/docs/0.10/deploying/uwsgi/)
* [How To Serve Flask Applications with uWSGI and Nginx on Ubuntu 14.04 | DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-uwsgi-and-nginx-on-ubuntu-14-04)
* [How To Deploy Flask Web Applications Using uWSGI Behind Nginx on CentOS 6.4 | DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-deploy-flask-web-applications-using-uwsgi-behind-nginx-on-centos-6-4)
* [Set up Django, nginx and uwsgi](https://gist.github.com/evildmp/3094281)