Djangoのデプロイ（Nginx, Gunicorn, Ubuntu）

Djangoで作成したWebアプリケーションをUbuntuサーバーにとりあえずデプロイする方法です。
セキュリティ設定等は、考慮してません。

# 構成
![構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3770088/8052a9fe-1e2c-0cd6-1281-5a49f50b6765.png)
Django,Gunicornは、Pythonの仮想環境にインストールします。
# 前準備
manage.pyのrunserverを使用していた環境から、settings.pyを書き換えます。
DEBUGをFalseにすると、STATIC_URLからSTATIC_ROOTに変わるようです。
`python3 manage.py collectstatic`を実行した際に、STATIC_ROOTにコピーされます。
Nginxの設定で、staticファイルは、/usr/share/nginx/html/staticからレスポンスするように設定します。
```python:mysite/settings.py
#DEBUG = True
DEBUG = False
#STATIC_ROOT = BASE_DIR / 'static'                                          
STATIC_ROOT = '/usr/share/nginx/html/static'
```
.gitignoreを以下の様に記述して、PCで作成したWebアプリケーションをGitHubにコードをプッシュして下さい。
```.gitignore
*.pyc
*~
/.vscode
__pycache__
myvenv
db.sqlite3
/static
.DS_Store
```
# サーバー側前準備
ubuntuサーバーにpythonのpip,venvとgitをインストールします。
ubuntuは、始めからsudoが使用できますが、sudoが使えない場合は、以下のコマンドでsudoに追加後、一度、ログアウト/ログインして下さい。
```
su -
apt install sudo
usermod -aG sudo user_name
```
```bash
sudo apt install python3-pip
sudo apt install python3-venv
sudo apt install git
```
sudo権限を削除する場合
```
sudo deluser user_name sudo
```

# Git clone
Githubにプッシュしたアプリケーションをクローンします。
GITHUB-ACCOUNT：githubのアカウント名
REPOSITORY：このアプリのリポジトリ名
```bash
git clone https://github.com/GITHUB-ACCOUNT/REPOSITORY.git
```
以降、作成されたREPOSITORYフォルダで作業します。
```
cd REPOSITORY
```
# Python仮想環境作成
Django,Gunicornをインストールするための仮想環境を作成します。
仮想環境フォルダ名は、myvenvとしています。
```bash
python3 -m venv myvenv
```
# Dangoインストールと設定
仮想環境を有効にして、Djangoをインストールして、マイグレーションと管理者ユーザーを作成します。
YOUR-APP：このアプリの名前
```bash
. myvenv/bin/activate
python3 -m pip install django
python3 manage.py migrate
python3 manage.py migrate YOUR-APP
python3 manage.py createsuperuser
```
# Gunicornのインストールと設定
仮想環境にGunicornをインストールします。
Gunicornのsocketとserviceファイルを作成します。
USERNAME：OSのユーザー名
REPOSITORY：このアプリのリポジトリ名（クローン時に作成されたフォルダ名）
```bash
python3 -m pip install gunicorn
sudo bash -c "cat > /etc/systemd/system/gunicorn.socket << EOL   
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
EOL"

sudo bash -c "cat > /etc/systemd/system/gunicorn.service << EOL
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=USERNAME
Group=www-data
WorkingDirectory=/home/USERNAME/REPOSITORY
ExecStart=/home/USERNAME/REPOSITORY/myvenv/bin/gunicorn --access-logfile - --worker s 3 --bind unix:/run/gunicorn.sock mysite.wsgi:application

[Install]
WantedBy=multi-user.target
EOL"
```
# Gunicornの起動
Gunicornを起動して、常駐します。
```bash
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
```
# Nginxのインストールと設定
Nginxをインストールして、設定します。
Djangoのstaticを/usr/share/nginx/html/staticにコピーします。
nginxを再起動します。
USERNAME：OSのユーザー名
SERVER-IP-ADDRESS：サーバーのIPアドレス、サーバー名等、ブラウザからこのアドレスにアクセスする
```bash
sudo apt install -y nginx
sudo mkdir /usr/share/nginx/html/static
sudo chown USERNAME /usr/share/nginx/html/static
sudo bash -c "cat > /etc/nginx/sites-available/YOUR-APP << EOL
server {
    listen 80;
    server_name SERVER-IP-ADDRESS;
    location /static {
        alias /usr/share/nginx/html/static;
    }
    location = /favicon.ico { access_log off; log_not_found off; }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}
EOL"
sudo ln -s /etc/nginx/sites-available/YOUR-APP/etc/nginx/sites-enabled/
python3 manage.py collectstatic
sudo service nginx restart
```
# インストールスクリプト
以上の操作を行うシェルスクリプトです。
### 前準備の確認シェルスクリプト
python3,pip,venv,sudo,gitがインストール済みであるか確認します。
```. check.sh```で起動して下さい。
```bash:check.sh
result=0
echo "インストールチェック"
echo "python3チェック"
python3 --version &> /dev/null
if [ $? -ne 0 ] ; then
	echo "python3 NG"
	result=-1
else
	echo "python3 OK"
    echo "pip3チェック"
	pip3 -V &> /dev/null
	if [ $? -ne 0 ] ; then
		echo "pip3    NG"
		result=-1
	else
		echo "pip3    OK"
	fi
    echo "venvチェック"
	python3 -m venv myvenv &> /dev/null
	if [ $? -ne 0 ] ; then
		echo "venv    NG"
		result=-1
	else
		echo "venv    OK"
	fi
    rm -rf myvenv
    echo "sudoチェック"
    str=`getent group sudo`
    substr=`whoami`
    if [[ "$str" =~ .*"$substr".* ]]; then
        echo "sudo    OK"
    else
        echo "sudo    NG"
		result=-1
    fi
    echo "gitチェック"
    git --version &> /dev/null
    if [ $? -ne 0 ] ; then
    	echo "git    NG"
    	result=-1
    else
    	echo "git    OK"
    fi
	if [ $result -ne 0 ] ; then
		echo "install NG"
	else
		echo "install OK"
    fi
fi
```
### デプロイシェルスクリプト
以下の作業を行います。
Gitのclone
Pythonの仮想環境作成
Djangoのインストール,migrate,管理者ユーザーの作成
Gunicornのインストール、設定、起動
Nginxのインストール、設定、起動
インストールしたいディレクトリで```. django-deploy.sh GITHUB-ACCOUNT REPOSITORY YOUR-APP```で起動して下さい。
GITHUB-ACCOUNT：クローンするレポジトリがあるアカウント（英数大文字小文字と数字と_と-が使用できます）
REPOSITORY：クローンするレポジトリ（英数大文字小文字と数字と_と-が使用できます）
YOUR-APP：Djangoのアプリ名（英数小文字と_が使用できます）
2行目のenp0s3は、各自の環境で編集する必要があるかもしれません。```ip a```でインターフェース名を調べて下さい。enp0s3は、VirtualBoxの場合です。
Nginxの設定で、server_nameは、PCのIPアドレスになっています。
運用に合わせて、修正して下さい。
```bash:deploy.sh
username=`whoami`
ip=`ip -f inet -o addr show enp0s3|cut -d\  -f 7 | cut -d/ -f 1`
if [ $# -ne 3 ];then
    echo "Usage: $0 GITHUB-ACCOUNT REPOSITORY YOUR-APP"
else
    x=`echo $1 | tr -d "[a-z][A-Z][0-9]_-"`
    if [ -n "$x" ]; then
        echo "Usage: $0 GITHUB-ACCOUNT REPOSITORY YOUR-APP"
        echo "GITHUB-ACCOUNTには[a-z][A-Z][0-9]_-だけ使えます。"
    else
        y=`echo $2 | tr -d "[a-z][A-Z][0-9]_-"`
        if [ -n "$y" ]; then
            echo "Usage: $0 GITHUB-ACCOUNT REPOSITORY YOUR-APP"
            echo "REPOSITORYには[a-z][A-Z][0-9]_-だけ使えます。"
        else
            z=`echo $3 | tr -d "[a-z]_"`
            if [ -n "$z" ]; then
                echo "Usage: $0 GITHUB-ACCOUNT REPOSITORY YOUR-APP"
                echo "YOUR-APPには[a-z]_だけ使えます。"
            else
                echo "Djangoプロジェクトのクローン"
                git clone https://github.com/$1/$2.git
                cd $2
                python3 -m venv myvenv
                echo "Django インストール"
                . myvenv/bin/activate
                python3 -m pip install django
                echo "Django migrate"
                python3 manage.py migrate
                python3 manage.py migrate $3
                echo "Django 管理者ユーザー作成"
                python3 manage.py createsuperuser
                echo "Gunicornのインストール"
                python3 -m pip install gunicorn
                echo "nginxのインストール"
                sudo apt install -y nginx
                echo "Gunicorn設定ファイルの作成"
sudo bash -c "cat > /etc/systemd/system/gunicorn.socket << EOL
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
EOL"
sudo bash -c "cat > /etc/systemd/system/gunicorn.service << EOL
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=$username
Group=www-data
WorkingDirectory=/home/$username/$2
ExecStart=/home/$username/$2/myvenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock mysite.wsgi:application

[Install]
WantedBy=multi-user.target
EOL"
                echo "Gunicorn起動" 
                sudo systemctl start gunicorn.socket
                sudo systemctl enable gunicorn.socket
                echo "nginx用staticフォルダ作成" 
                sudo mkdir /usr/share/nginx/html/static
                sudo chown $username /usr/share/nginx/html/static
                echo "nginx設定ファイルの編集" 
sudo bash -c "cat > /etc/nginx/sites-available/$3 << EOL
server {
    listen 80;
    server_name $ip;
    location /static {
        alias /usr/share/nginx/html/static;
    }
    location = /favicon.ico { access_log off; log_not_found off; }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}
EOL"
                echo "nginx設定ファイルのシンボリックリンク作成" 
                sudo ln -s /etc/nginx/sites-available/$3 /etc/nginx/sites-enabled/
                echo "staticコピー" 
                python3 manage.py collectstatic
                echo "nginx再起動" 
                sudo service nginx restart
                deactivate
            fi
        fi
    fi
fi
```
# 参考ページ
色んなページを参考にしましたが、Gunicornの起動コマンドが```gunicorn --bind 0.0.0.0:8000 Djangoアプリ名.wsgi:application```となっていて、Gunicornが起動できずに、悩みました。
```gunicorn --bind 0.0.0.0:8000 mysite.wsgi:application```にすることで起動できました。
Djangoのwsgi.pyファイルの位置が変わったのかもしてません。
#### 追記
mysite/settings.pyに`WSGI_APPLICATION = 'mysite.wsgi.application'`とあるので、ここを参照すればいいのかと思います。