CentOSでFlaskを導入してからNginxとuWSGIでサービス化するまで

CentOSもWebサーバの構築も無知な自分が，Flask・Nginx・uWSGIに足を踏み入れた話．
その手順をここにまとめておく．

[](過程で起こった様々な苦難の掃き溜めは別記事で↓)

## 前提
- OS : CentOS 7
- root権限が付与されたユーザ
- Pythonの仮想環境にはpipenvを使う

## 準備
### 登場人物
適宜置き換えて読むべし．

`user` : ユーザ名
`proj` : プロジェクトのディレクトリ
`test.py` : Flaskを動かすコードを書く．projの直下に配置

### 作業は常時プロジェクトディレクトリ下で行う

```sh
$ cd /home/user/proj
```

## Flaskの導入

Flaskを使い，PythonでWebアプリを簡単に作れるようにするための環境を作る．

### Python3のインストール

```sh
$ sudo yum install epel-release  # リポジトリを入れる
$ sudo yum install python3-devel  # python3を入れる
```

### 仮想環境を作る
```sh
$ pip3 install pipenv  # pipenvを導入
$ export PIPENV_VENV_IN_PROJECT=true  # 仮想環境をプロジェクトディレクトリ内に作るように設定
$ pipenv --python 3  # 仮想環境の生成
```

```sh
$ ls -a  # ファイル一覧を確認
```
`.venv`ができてるのが確認できればOK．

### 必要なモジュールのインストール
最低限必要なのはこれだけ．

```
$ pipenv install flask markupsafe
```

移行のときに困りたくなければ，`pip`ではなく`pipenv`でインストールすること．
他に必要なモジュールがあったら，同様に`pipenv install`で入れる．

## Flaskを使ってみる
### Flaskを書く
`test.py`を作る．

```sh
$ vi test.py
```

`i`で挿入モードに入り，以下を記述．
書き終わったら`Esc`→`:wq`で抜ける．

```python:test.py
from flask import *

app = Flask(__name__)

@app.route("/")
def main():
    return 'Hello, World!\n'

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

トップページにアクセスされたら'Hello, World!'を出力するだけのコードである．

### Flaskの実行
いくらモジュールをインストールしようが，仮想環境に入らないことには始まらない．

```sh
$ pipenv shell  # 仮想環境に入る
```

`test.py`を実行！

```
$ python test.py
```

Google Chrome等のブラウザで，これを実行したサーバのIPアドレスを打ち込んでアクセスする．
'Hello, World!'と表示されたらOK．
ターミナルに戻り，`Ctrl+C`で実行を止める．

## Nginxの導入

Nginxを用いたWebサーバの導入．
[](もし既にApache等を使っていて，これを機にApacheとは決別したいなら[こちら]()．)

### Nginxのインストール
まず`nginx.repo`をvim等で開く．

```sh
$ sudo vi /etc/yum.repos.d/nginx.repo
```

以下を記述．

```:nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
```

### HTTPポートの開放

ファイアウォールがHTTPサービスを許可するように設定．

```sh
$ sudo firewall-cmd --add-service=http --zone=public --permanent
$ sudo firewall-cmd --reload
```

### Nginxの起動

```sh
$ sudo systemctl start nginx  # 即時起動
$ lsof -i:80  # nginxが表示されればOK
```

## uWSGIの導入

uWSGIは，FlaskとNginxの仲介役となるアプリケーションサーバ．

### uWSGIのインストール

```sh
$ pipenv install uwsgi
```

### 設定ファイルの作成

```sh
$ vi test_uwsgi.ini
```

以下を記述．

```:test_uwsgi.ini
[uwsgi]
base = /home/user/proj
app = test
module = %(app)
virtualenv = /home/user/proj/.venv
pythonpath = %(base)
socket = /tmp/test_uwsgi.sock
chmod-socket = 666
callable = app
logto = /home/user/proj/log/%n.log
```

自分でアレンジしたいなら↓
[uWSGIのiniファイルの文法まとめ](https://qiita.com/11ohina017/items/da2ae5b039257752e558
)

ログ用のディレクトリも作っておく．

```sh
$ mkdir log
```


### Nginx側の設定

`proj`ディレクトリの下でNginx用の設定ファイルを作る．

```sh
$ vi test_nginx.conf
```

以下を記述．

```:test_nginx.conf
server {
  listen      80;
  server_name [IPアドレス];
  charset     utf-8;

  location / { try_files $uri @yourapplication; }
  location @yourapplication {
    include uwsgi_params;
    uwsgi_pass unix:/tmp/test_uwsgi.sock;
  }
}
```

Nginxが起動時にこれを参照できるように，シンボリックリンクを配置する．

```sh
sudo ln -s /home/user/proj/test_nginx.conf /etc/nginx/conf.d/
```

必ず絶対パスで指定すること．

### (Optional) SELinuxを無効化する

SELinuxは，Linux内部でのアクセスの監視と制御を常時行ってるらしい．
PCに侵入されたときの被害を最小限に抑えるためだとか．
Nginx起動時にエラーを吐かれる場合は，以下のようにすることで解決できるかも．

```sh
$ setenforce 0
```

これでアクセス制御はオフになる．
Permissiveモードになるだけで完全なオフになるわけではないらしい．

再起動しても元に戻らないよう，設定ファイル自体も編集する．

```sh
$ vi /etc/selinux/config  # "SELINUX=enforcing"を"SELINUX=permissive"に書き換える
```

SELinuxを使わなくても，セキュリティ的に大丈夫なのか？
使うに越したことは無いけど，ファイアーウォールとかしっかり設定しとけばまぁ大丈夫でしょ，という結論に．

### uWSGI動作確認

```sh
$ sudo systemctl restart nginx  # SELinuxをオフにしないとここでエラーを吐くかも
$ uwsgi --ini test_uwsgi.ini  # 設定ファイルからuWSGIを起動
```

ブラウザをリロードし，'Hello, World!'と表示されればOK．


## サービス化

サーバ起動時に，これらが自動で起動されるようにする．

### uWSGIのサービス用の設定ファイルを作る

```sh
vi /etc/systemd/system/uwsgi.service
```

以下を記述．

```:uwsgi.service
[Unit]
Description=uWSGI
After=syslog.target

[Service]
ExecStart=/home/user/proj/.venv/bin/uwsgi --ini /home/user/proj/test_uwsgi.ini
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all

[Install]
WantedBy=multi-user.target
```

```sh
$ cat /lib/systemd/system/nginx.service  # 今書いたものが表示されればOK
```

### サービスの設定

```sh
$ sudo systemctl daemon-reload  # uwsgi.serviceの再読み込み
$ sudo systemctl enable uwsgi nginx  # uWSGIとNginxのサービスを有効化
```

サーバを再起動してみて，ブラウザで確認．'Hello, World!'と表示されればOK．
お疲れ様でした！！

## 参考
- [Flask + uWSGI + Nginx でハローワールドするまで @ さくらのVPS (CentOS 6.6)](https://qiita.com/morinokami/items/e0efb2ae2aa04a1b148b)
- [ConoHa VPS(CentOS 7.6)でFlask + Nginx + uWSGIのWebアプリ(複数)実行環境構築](https://qiita.com/yuucu/items/802549beb90fc8e9f228)
- [NginxとuWSGIでHelloWorld](https://qiita.com/koyoru1214/items/57461b920dfc11f67683)
- [ちゃんと運用するときのuWSGI設定メモ](https://qiita.com/yasunori/items/64606e63b36b396cf695)