Ubuntu22.04にてDjango + nginx + gunicorn + MySQLで本番環境の作成

# 概要
Djangoのアプリを作成した後、本番環境(ローカル)へデプロイをした際に、躓いたのでメモがわりに記載します。
つまづいたポイントとして、DjnagoアプリとNginxの連携が上手くいかず、本来表示される予定のページにてHelloページ(デフォルトページ)が表示されたことです。
もし、同じ悩みを持った人や同じことをしようとしている人がいれば参考にしていただければ幸いです。

※誰でも理解できるように記載を行っているつもりですが、ある程度のDjangoの知識が必要だと思います。
# 前提
前提として、Djangoアプリの開発が完了 + MySQLの構築 + Nginxのインストールが完了している程で進みます。これらができていない方は、こちらの方々の記事を参考にすると構築ができると思います。

MySQLの構築:

https://qiita.com/lustm5/items/18dcea509e190a62e83a

nginx(最新)のインストール:

https://qiita.com/lustm5/items/aabd365aaeb873e7b17a

+ フレームワーク: Django == 4.2.5
+ DB: MySQL == 8.0.34
+ APサーバ: Gunicorn == 21.2.0
+ Webサーバ: Nginx == 1.24.0
+ Python: python3.10.12


# 使用した環境
重要なのはサーバのOSだけだと思いますが記載します。
+ server
    + OS: Ubuntu22.04 LTS
+ client
    + OS: MacOS Ventura 13.4.1(c)

# 構想
以下の構想で実装を行いました。

![server_image_page-0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115813/ce3da788-7ebf-29bd-c03d-c6c9d5c40cb6.jpeg)


# ディレクトリ構想
重要なのはyourproject/yourproject/settings.pyのみです。app1などはそれぞれのアプリを指します。
```ruby:
.
├── bin # 仮想環境
└── yourproject # それぞれのプロジェクト
    ├── app1
    ├── app2
    ├── app3
    ├── yourproject
    │   ├── __init__.py
    │   ├── asgi.py
    │   ├── settings.py # 今回はここだけ変更します
    │   ├── urls.py
    │   └── wsgi.py
    └── templates
        ├── app1
        ├── app2
        └── app3

```
# 手順

1. Djangoアプリケーションの作成(ここは省略させていただきます) 

2. apt、pipの更新

    ```ruby:
    sudo apt update
    python3 -m pip install --upgrade pip
    ```
3. virtualenvのインストール
     ```ruby:
    python3 -m pip install virtualenv
    ```

4. 仮想環境の構築とアクティブ化
    ```ruby:
    $ sudo apt install python3.10-venv
    $ python3 -m venv .
    $ source bin/activate 
    ```
    ここまでが完了したらターミナルのユーザ名の前に
    (作業しているディレクトリ名)hoge@hoge:~/...$みたいに記載されているはずです。

5. 仮想環境に必須なものをインストール

    ```ruby:
    $ python3 -m pip install django gunicorn psycopg2-binary
    $ sudo apt install curl
    ```

    上記のものは必須です。
    その他必要なものもこの時にpipしておきましょう。
    後に、runserverした時に不足しているものは表示されるので随時インストールでもokです。

6. Djangoアプリのsettings.pyを編集
    ```ruby: yourproject/yourproject/settings.py
    $ cd yourproject/yourproject
    $ vi settings.py

    # 以下の部分を編集してください
    ALLOWED_HOSTS = ['*']

     # importのみファイルの先頭に記載
    import os
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

    ```
    編集できたらエディタは何を使っても構いません。vscodeでもokです。

    :::note warn
    今回はセキュリティは考慮していません。従って、ALLOWED_HOSTS = ['*']としていますが、本来であれば、使うIPだけを許可してください

7. データベースのマイグレーションとアドミンユーザの作成
    ```ruby: yourproject
    $ python3 manage.py makemigrations
    $ python3 manage.py migrate
    $ python3 manage.py createsuperuser
    # コンソールに色々記載しますが、推測されないユーザを作りましょう。
    ```

    すでにマイグレーションとアドミンユーザを作っている場合は飛ばして構いません
    
8. staticファイルの収集
     ```ruby: yourproject
    $ python3 manage.py collectstatic
    ```


9. ファイアウォールの設定
     ```ruby: yourproject
    $ sudo ufw allow 8000
    ```

10. Djangoアプリが起動するか確認

     ```ruby: yourproject
    $ python3 manage.py runserver
    ```

11. Gunicornを使って起動するか確認

     ```ruby: yourproject
    $ gunicorn --bind 0.0.0.0:8000 yourproject.wsgi
    ```
    settings.pyがあるディレクトリに各自移動して実行してください。
    一旦、ブラウザで
    http://自分のip:8000
    を見てアプリの画面が出ていたらokです。

12. systemdソケットの作成

     ```ruby:
    $ sudo vi /etc/systemd/system/gunicorn.socket

    # 以下の内容を記載してください
    [Unit]
    Description=gunicorn socket
    [Socket]
    ListenStream=/run/gunicorn.sock
    [Install]
    WantedBy=sockets.target

    ```

13. サービスファイルの作成

     ```ruby:
    $ sudo vi /etc/systemd/system/gunicorn.service

    # 以下の内容を適宜変更して記載してください("()"は必ず削除してください)
    [Unit]
    Description=gunicorn daemon
    Requires=gunicorn.socket
    After=network.target
    [Service]
    User=sammy（Ubuntuのユーザー名）
    Group=sammy (Ubuntuのユーザ名でok)
    WorkingDirectory=/home/sammy/yourprojectdir (settings.pyの一個上の階層のパス)
    ExecStart=/home/sammy/yourprojectdir/bin/gunicorn \ (bin/gunicornのあるパス)
              --access-logfile - \
              --workers 3 \
              --bind unix:/run/gunicorn.sock \
              yourproject.wsgi:application（yourprojectは作成したアプリ名）
    [Install]
    WantedBy=multi-user.target
    ```

    その他の設定(タイムアウト)は，公式ドキュメントを参考にしてください．
    https://docs.gunicorn.org/en/stable/settings.html

13. Gunicornソケットの実行とソケットのアクティブ化

     ```ruby:
    $ sudo systemctl start gunicorn.socket
    $ sudo systemctl enable gunicorn.socket
    $ sudo systemctl status gunicorn.socket
    ```
    statusでActiveがactiveになっておればokです。あとはgunicorn.socketの前に緑色の⚪︎があれば起動完了です。

14. Gunicorn.sockのファイルがあるか確認

     ```ruby:
    $ file /run/gunicorn.sock
    # 下記の画面が表示されたらok
    /run/gunicorn.sock: socket
    ```
    :::note info
    ここでつまづいたら、おそらくソケットの作成ができていません。従って下記のコマンドでデバッグしましょう。
    ```ruby:
    $ sudo journalctl -u gunicorn.socket
    ```

    :::

15. 疎通確認

     ```ruby:
    $ sudo systemctl status gunicorn
    $ curl --unix-socket /run/gunicorn.sock localhost

    # ここでhtmlのレスポンス(200)が返却されたらokです。 
    $ sudo systemctl daemon-reload
    $ sudo systemctl restart gunicorn
    $ sudo systemctl start nginx
    ```

16. nginxのGunicornのプロキシを設定

     ```ruby:
    $ sudo vi /etc/nginx/conf.d/yourproject.conf

    # 下記の内容を適宜変更して記載してください
    server {
        listen 80;
        server_name server_IP;
        location = /favicon.ico { access_log off; log_not_found off; }
        location /static/ {
            root /home/sammy/yourprojectdir;
        }
        location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://unix:/run/gunicorn.sock;
         }
    }

    $ sudo rm /etc/nginx/conf.d/default.conf
    ```

    この時にインデントに注意してください。筆者はここのインデントを間違えて躓いていました。

17. nginxに間違いがないか確認

     ```ruby:
    $ sudo nginx -t
    # 下記の画面が表示されたらok
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful

    $ sudo systemctl restart nginx
    ```

18. ファイアウォールの設定
    ```ruby:
    $ sudo ufw delete allow 8000
    $ sudo ufw app list
    $ sudo ufw allow 80,443/tcp
    $ sudo vi /etc/ufw/applications.d/nginx.ini

     # 下記の内容を記載

    [Nginx HTTP]
    title=Web Server 
    description=Enable NGINX HTTP traffic
    ports=80/tcp
    
    [Nginx HTTPS] \
    title=Web Server (HTTPS) \
    description=Enable NGINX HTTPS traffic
    ports=443/tcp
    
    [Nginx Full]
    title=Web Server (HTTP,HTTPS)
    description=Enable NGINX HTTP and HTTPS traffic
    ports=80,443/tcp

    $ sudo ufw app update nginx
    $ sudo ufw app info 'Nginx HTTP'
    $ sudo ufw allow 'Nginx HTTP'
    $ sudo ufw allow 'Nginx Full'
    $ sudo ufw status
    $ sudo ufw enable
    ```

20. 疎通確認(最後)
http://自分のip
にアクセスを行うと、Djangoのアプリが見れるはずです。(もしかしたらcssが崩れている可能性があります)

# 終わりに
同じ悩みの人が実行できていれば幸いです。
余談ですが、やはりDockerを用いた方が簡単なのでしょうか?有識者の方がいたら教えていただきたいです。
また間違い等がございましたら、ご連絡ください。
最後まで見ていただきありがとうございました。

# 参考文献


https://asameshicode.com/how-to-deploy-django-with-ubuntu/

https://medium.com/analytics-vidhya/dajngo-with-nginx-gunicorn-aaf8431dc9e0

https://qiita.com/lustm5/items/75707e10abee58e9dff3