MySQL × Nginx × uWSGI を用いて、Debian 上に pipenv でパッケージ管理された python 3.9 の Django アプリをデプロイ

一つの Debian インスタンス上に全て（MySQL・Nginx・uWSGI）のプロセスを積み込み、 Django アプリをデプロイする手順のメモを作成したので公開。とりあえずちょっとしたアプリを公開したい場合などを想定。

## 構成

Debian 10
Nginx <-> uWSGI <-> Django <-> MySQL

動作確認時のバージョン：

* python 3.9.7

* Django 3.2.7

## 前提

`username` ユーザー（適宜変更）として作業可能な Debian 環境 (AWS EC2 や GCP GCE などで Debian インスタンスを作成など) が準備できている。

## 必要になる apt パッケージのインストール

```
~$ sudo apt update
~$ sudo apt -y install build-essential zlib1g-dev libncurses5-dev libgdbm-dev \
   libnss3-dev libssl-dev libsqlite3-dev libreadline-dev libffi-dev libbz2-dev \
   curl git default-mysql-server default-libmysqlclient-dev nginx libpcre3-dev
```

## python 3.9 のインストール

[参考](https://linuxize.com/post/how-to-install-python-3-9-on-debian-10/) の方法を参考に、真面目にインストールする(数十分かかる)。

```
~$ curl -OL https://www.python.org/ftp/python/3.9.7/Python-3.9.7.tgz
~$ tar -xf Python-3.9.7.tgz
~$ cd Python-3.9.7
~/Python-3.9.7/$ ./configure --enable-optimizations
~/Python-3.9.7/$ make -j 2
~/Python-3.9.7/$ sudo make install
```

## pipenv のインストール

```
~$ pip3 install pipenv
```

## pipenv の PATH を通す

```
~$ vim ~/.bashrc
```

.bashrc に追記する内容は下記。

```shell:.bashrc
export PATH=$PATH:/home/dev/.local/bin
```

## Git ホスティングサービスとの SSH 接続

本記事では省略します。 GitHub なら [こちら](https://qiita.com/shizuma/items/2b2f873a0034839e47ce) 、 Bitbucket なら [こちら](https://qiita.com/0084ken/items/e763c85054a5a1e2cc6c) などをご参照ください。

## リポジトリの clone / pipenv install

リモートリポジトリ名を `my`, 作業ユーザー名を `username` とする（適宜変更）。

```
~$ cd /
/$ sudo chown username var
/$ cd var
/var/$ sudo chown username www
/var/$ cd www
/var/www/$ git clone <リモートリポジトリ>
/var/www/my/$ pipenv install --system
```

## uWSGI / Nginx の設定

[参考](https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html)

uwsgi_params ファイルの作成

```
~$ vim /var/www/my/uwsgi_params
```

```shell: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;
```

uwsgi のログファイルと uwsgi.ini ファイルの作成

```
~$ sudo mkdir /var/log/uwsgi
~$ sudo touch /var/log/uwsgi/uwsgi.log
~$ vim /var/www/my/uwsgi.ini
```

```shell:uwsgi.ini
chdir = /var/www/my/
module = config.wsgi
master = true
processes = 1
socket = /var/www/my/my.cock
chmod-socket = 666
logto = /var/log/uwsgi/uwsgi.log
```

Nginx の設定ファイル my_nginx.conf の作成とその設定の有効化

```
~$ sudo vim /etc/nginx/sites-available/my_nginx.conf
```

```nginx:my_nginx.conf
server {
    listen 80;
    server_name <インスタンスの IP アドレス>;
    charset utf-8;

    client_max_body_size 75M;

    location / {
        uwsgi_pass unix:///var/www/my/my.sock;
        include /var/www/my/uwsgi_params;
    }
}
```

```
~$ sudo ln -s /etc/nginx/sites-available/my_nginx.conf /etc/nginx/sites-enabled/
~$ sudo systemctl restart nginx
```

## データベースの設定

データベース名を `mydb`, ユーザー名を `username`, パスワードを `mypassword` とする（適宜変更）。

```
~$ sudo mysql -uroot
mysql> create database mydb;
mysql> create user 'username'@'localhost' identified by 'mypassword';
mysql> grant all privileges on my.* to 'username'@'localhost';
~$ vim /var/www/my/config/settings.py
```

```python:settings.py
...

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mydb',
        'USER': 'username',
        'PASSWORD': 'mypassword',
    }
}

...
```

## アプリの起動

（※注： Django の settings ファイルで `DEBUG = True` となっているなら、 `DEBUG = False` にしておく。）

```
~$ cd /var/www/my
/var/www/my/$ python3 manage.py migrate
/var/www/my/$ uwsgi --ini uwsgi.ini &
```

以上でアプリが公開されるはず（クラウドのインスタンスなら `http://<インスタンスの ip アドレス>` を確認）。

以上です。閲覧ありがとうございました！