uWSGI ✖️ nginx ✖️ Djangoをローカル環境で試した時に詰まった話【自分用メモ】

## はじめに
[大高隆・著「動かして学ぶ！Python Django開発入門」](https://www.amazon.co.jp/dp/B07YY5RDPC/ref=cm_sw_r_tw_dp_U_x_TCsYEbRH6SF0V)を使用して
python・Djangoの学習を始めた初学者です。
ruby・railsを使用して4ヶ月ほどプログラミングの勉強をしていましたが、
エンジニア転職にあたり、pythonを使用することになったのでこの本を片手に勉強を始めました。
ド級の素人なので、補足・ご指摘等コメントいただけると大変助かります。

## 概要
いよいよアプリをデプロイ目前。
その前に、nginx✖️djangoの接続を勉強するため、
ローカル環境でセットアップを試してみました。

初心者の自分には断片的であったり問題解決につながる記事が少なかったので、
自分用メモとして記事を残しておきます。

やり方としては下記の公式ドキュメントに沿って行いました。
ドキュメントに沿って詰まった点の補足を自分に向けてコメントします。
[Setting up Django and your web server with uWSGI and nginx](https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html)
※この先登場する文章中のリンクについては、全てこのドキュメント内の該当箇所になります。

## 環境
- python3.8.2
- django3.0.7
- uWSGI2.0.19.1
- nginx1.19.3
- macOS Catalina10.15.6

## やりたいこと
クライアント ⇄ webサーバ(nginx) ⇄ APサーバ(uWSGI) ⇄ Djangoアプリ
の流れを作りたい。

使用しているものについては、なんとなくの理解の部分が多いので、
別途参考記事をみて理解いただくのが最善かと思います。
・[nginx・uWSGIについての参考記事](https://ushinji.hatenablog.com/entry/2019/09/15/215111)

djangoでのプロジェクト作成方法等もここでは端折ります。
わからない場合は[このあたりに書いてあります。](https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html#before-you-start-setting-up-uwsgi)

## ディレクトリ構成
※一部省略しています。

```Project.
|--app1
|--app2
|--config(設定などなど)
|　　|--settings
|　　|　　|--base.py(開発・本番環境共通項目のsettings)
|　　|　　|--local.py(開発環境用のsettings)
|　　|　　└--production.py(本番環境用ののsettings)
|　　|--project_uwsgi.ini(チュートリアル中に作成)
|　　|--urls.py
|　　└--wsgi.py
|--static
|--manage.py
|--test.py(クライアント⇄uwsgi⇄python確認用)
└--uwsgi_params(チュートリアル中に作成)
```

## ポイント1
test.py を実行して、
クライアント ⇄ uWSGI ⇄ Python
の流れの確認まではすんなり.

そのあと、クライアント ⇄ uWSGI ⇄ Djangoの指定コードでは、

```ターミナル.
uwsgi --http :8000 --module mysite.wsgi
```

となっています。これを上記のディレクトリ構成に合わせると、

```ターミナル.
uwsgi --http :8000 --module config.wsgi
```

ちなみに指定している"wsgi.py"の中身ですが、まだ本番環境周りについては何も記述していないので、

```wsgi.py
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local')
```

としてエラーが出ない様に一旦"local.py"の方が読み込まれる様に便宜的にしています。
これで、**クライアント ⇄ uWSGI ⇄ Django**の流れが確認できました。

## ポイント2
nginxのインストールについて、自分はインストール済でしたが一応。
ドキュメント上だと、

```ターミナル.
sudo apt-get install nginx
sudo /etc/init.d/nginx start
```

となっていますが、自分は

```ターミナル.
brew install nginx
```

で入れておりました。問題なくいけました。

## ポイント3
uWSGIのおまじないファイルを作成します。[(この辺りです。)](https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html#configure-nginx-for-your-site)
中身については、思考停止で構わない様なので、完全にコピペです。
プロジェクト直下の**uwsgi_params**です。

```uwsgi_params.
uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;
```
もう一つnginxについてのファイルを作成します。
>This conf file tells nginx to serve up media and static files from the filesystem, as well as handle requests that require Django’s intervention. For a large deployment it is considered good practice to let one server handle static/media files, and another handle Django applications, but for now, this will do just fine.


ディレクトリはドキュメントの仰せの通りに、
**/usr/local/etc/nginx/sites-available/**内に作成しました。

```project_nginx.conf
# the upstream component nginx needs to connect to
upstream django {
    server unix:///Users/name/projects/project/project.sock;
}

# configuration of the server
server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name 127.0.0.1;
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;

    # 作成しているアプリの構成上、mediaは不要なので、
　　　 ここでは割愛しています。

    location /static {
        alias /Users/name/projects/project/static;
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /Users/name/projects/project/uwsgi_params;
    }
}
```

からの

```
sudo ln -s /usr/local/etc/nginx/sites-available/project_nginx.conf /usr/local/etc/nginx/sites-enabled/
```

を実行。"site-enabled"がない場合は作成しておきましょう。

## ポイント4
> Deploying static files
> Before running nginx, you have to collect all Django static files in the static folder. First of all you have to edit mysite/settings.py adding:

ということで、djangoアプリの静的ファイルを集める必要がある様です。
~~なぜかはよくわかりません。あとで調べてみます。~~

```base.py
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
```

をsetteingsに追加して、

```ターミナル.
python manage.py collectstatic
```

を実行。

```base.py
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
```

の記述を元からしてあったので、同じ様なもん出し、書かなくてもええやろ
と思っていましたが、ないとエラーになってしまいました。
そして、nginxを再起動。

```ターミナル.
sudo nginx -s stop
sudo nginx
```

これで

```ターミナル.
uwsgi --socket projecｔ.sock --wsgi-file test.py
```

を実行して、[パス](http://127.0.0.1:8000/)にアクセスして[HelloWorld]が表示されれば、
**クライアント ⇄ nginx ⇄ uWSGI ⇄ Python**
ができているという確認ができるよ、ということの様です。なるほど。

ちな、上記でエラーが出る時は、
**--chmod-socket=666**や**--chmod-socket=664**をつけて実行してみるとうまくいくかもと。
なるほど。

さらにさらに、

```
uwsgi --socket project.sock --module config.wsgi --chmod-socket=666
```

としてあげれば、ついに
**クライアント ⇄ nginx ⇄ uWSGI ⇄ django**の完成ですね。

最後に、"project_uwsgi.ini"を作成してあげることで、管理がしやすくなるということでconfig内に作成。

```project_uwsgi.ini
[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /Users/name/projects/project
# Django's wsgi file
module          = config.wsgi
# the virtualenv (full path)
home            = /Users/name/projects/project/venv/

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = /Users/name/projects/project/project.sock
# ... with appropriate permissions - may be needed
# chmod-socket    = 666
# clear environment on exit
vacuum          = true
```

こうすることで、

```ターミナル.
uwsgi --ini project_uwsgi.ini
```

とすると、先ほどと同じ様にDjangoアプリを起動することができました。

## 追記
そういえば、エラーが二つほど。
#### ①nginxの502エラー
↓
uwsgi --ini project_uwsgi.ini --chmod-socket=666
これでうまく起動してくれました。

#### ②[error] 52089#0: *24 kevent() reported that connect() failed (61: Connection refused) while connecting to upstream, client: 127.0.0.1, server: ※※※.※※※.※※.※, request: "GET / HTTP/1.1", upstream: "uwsgi://127.0.0.1:8001", host: "127.0.0.1:8000"
↓
nginxが起動していないだけだった。
ターミナルで"sudo nginx"で解決。

## まとめ
環境を作るって、難しい。

## 参考文献
- [大高隆・著「動かして学ぶ！Python Django開発入門」](https://www.amazon.co.jp/dp/B07YY5RDPC/ref=cm_sw_r_tw_dp_U_x_TCsYEbRH6SF0V)
- [Setting up Django and your web server with uWSGI and nginx](https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html)
- [「uWSGI」とアプリケーションサーバーについて](https://ushinji.hatenablog.com/entry/2019/09/15/215111)
- [nginxでDjangoを使うときの設定ファイル：クライアント、nginx、uwsgiの流れを整理しよう](https://www.mathpython.com/ja/django-nginx-conf/)
- [nginxでdjangoとuwsgi](https://qiita.com/akhkyamada/items/50ed69399dbbcbb0c1b7)