【Python】Nginx + uWSGI + Flask + Supervisorの環境構築【Ubuntu】

| 0件のコメント

Flask アプリケーションを Nginx でデプロイする時のメモです。

  • flask: 軽量WAF (Web Application Framework)
  • uWSGI: WSGI (Web Server Gateway Interface)
  • Nginx: リバースプロキシ (Reverse Proxy)
  • Supervisor: プロセス監視

uWSGI

環境は Ubuntu14.04(LTS) ですが, 基本的には CentOS では apt-get を yum に変更するだけだと思います。

$ sudo pip install flask
# dependent packages
$ sudo apt-get install libxml2-dev
$ sudo apt-get install libxslt1-dev 
$ sudo pip install uwsgi

先に uWSGI で Flask アプリを起動しておきます。
log出力先を /var/log/uwsgi.log としていますが, stdout/stderr も出力したい場合は Flaskで PROPAGATE_EXCEPTIONS=True を設定します。

$ nohup uwsgi -s /tmp/uwsgi.sock --module yourapp --callable app --chmod-socket=666 --logto /var/log/uwsgi.log --processes 4 &
$ ps aux | grep uwsgi

コマンドだと長いので, iniファイルにまとめておきます。

[uwsgi]
master = true
python-path = /your/project/path
wsgi = yourapp:app
chmod-socket = 666
callable = app
socket = /tmp/uwsgi.sock
logto = /var/log/uwsgi.log
processes = 4
threads = 2

ソースコードの変更は, uWSGIを再起動すると反映されます。

Nginx

Nginx をインストールします。

$ sudo apt-get install nginx
$ nginx -v
nginx version: nginx/1.4.6 (Ubuntu)

設定を変更します。8080 portで公開, 内部では UNIX domain socket で uWSGI に繋ぎます。ついでに, gzip を有効にします。
設定は Flask のDocsを参考にしました。また, リバースプロキシで Header を書き換えられたくないので, proxy_set_header を設定します。

$ sudo vim /etc/nginx/nginx.conf
...
        gzip on;
        gzip_proxied any;
        gzip_types text/css text/javascript application/javascript application/x-javascript application/json;
        expires 30d;

        server {
            listen 8080;
            server_name xxxxxxxx;

            location / {
                try_files $uri @yourapplication;
                proxy_set_header Host $host;
            }
                
            location @yourapplication {
                include uwsgi_params;
                uwsgi_pass unix:/tmp/uwsgi.sock;
            }
        }

再起動します。

$ sudo service nginx restart
$ ps aux | grep nginx

logはデフォルトでは以下です。

$ tail /var/log/nginx/access.log
$ tail /var/log/nginx/error.log 

実際に Client のリクエストが Accept-Encoding gzip, deflate の場合, http-response-header で Content-Encoding gzip になっていることを確認できます。

Supervisor

Supervisor でプロセス管理を行います。

$ sudo apt-get install supervisor

各プロセスの設定は /etc/supervisor/conf.d 以下に書きます。

$ vim /etc/supervisor/conf.d/uwsgi.conf
[program:uwsgi]
directory=/your/project/path
command=/usr/local/bin/uwsgi --ini uwsgi/uwsgi.ini
numprocs=1
autostart=true
autorestart=true
user=root
redirect_stderr=true
stdout_logfile=/var/log/supervisor/uwsgi.log

設定変更時は, supervisorctl reload で再起動します。設定ファイルが読み込まれるので, 変更があれば適用し各プロセスを起動します。

$ sudo service supervisor start uwsgi
$ sudo supervisorctl status
uwsgi                        STARTING

試しに kill して, restart されるか確認してみます。

$ sudo killall uwsgi
$ ps aux | grep uwsgi
root     27901  0.0  2.4  98380 25304 ?        S    23:34   0:00 /usr/local/bin/uwsgi --ini uwsgi/uwsgi.ini

TimeZone変更

対話形式で TimeZone を Tokyo に変更します。

$ sudo dpkg-reconfigure tzdata

FlaskでCookieの属性設定

Cookieを扱う際, http と https が混在しているサイトでは http 通信時に Cookie を平文で送信してしまいます。Secure属性を追加することで https 通信時のみ Cookie を送信します。また, HttpOnly属性を追加することで通信時のHTTPヘッダ以外, JavaScript から Cookie にアクセスすることを禁止します。

Flaskでは下記のように設定します。

app.config.update(
	SESSION_COOKIE_SECURE=True,
	SESSION_COOKIE_HTTPONLY=True
)

Chrome developer tools > Resources > Cookies で確認できます。
下記で HTTP が HttpOnly属性, Secure が Secure属性 です。

flask-cookie-secure

余談ですが uWSGI 起動時に if __name__ == “__main__”: の中で app.run()しないと, unable to load configuration from uwsgiで怒られる。
Errorメッセージと原因の関係性がわかりにくいです…

[1] Flask-Viewsのmodule化のアイデア
[2] Flask and uWSGI – unable to load app 0 (mountpoint=”) (callable not found or import error)
[3] supervisorctlについて調べてみた
[4] SupervisorでPythonのWebアプリをデーモン化する

コメントを残す

必須欄は * がついています