💻

【Django】AWSのEC2にnginx+gunicornでDjangoのアプリをデプロイする方法

2023/12/30に公開

前提

  1. Djangoのアプリは作成済みで、DBはmysqlを使用している。githubで管理していてそこからクローンする。
  2. EC2はAmazonLinux2を使用する。

EC2でサーバーを立てる

AMIはAmazonLinux2で立てる。
パブリックIPを有効にするのを忘れない。
セキュリティグループのインバウンドは、以下の設定にする。
HTTP 80 0.0.0.0
SSH 22 0.0.0.0
カスタムTCP 8000 0.0.0.0

必要なものをインストールする

EC2で立てたサーバーに接続し、その中で以下のコマンドを打つ。

sudo passwd ec2-user
sudo passwd root
sudo yum update
sudo yum install python3
sudo yum install git
sudo amazon-linux-extras install nginx1
sudo pip3 install django
sudo pip3 install gunicorn

Djangoのアプリの設定を行う

githubからDjangoアプリをクローンする

まずはgithubからクローンしてくるため、SSHキーを作成する。
下記のコマンドを打ち、3回エンターを押せば作成できる。

ssh-keygen

次に、以下のコマンドで公開鍵の方を表示して、それをgithubの設定からSSH keysに行き、公開鍵を張り付けてクローン出来るようにする。

cd ~/.ssh
cat id_rsa.pub

これでクローンの準備は整ったが、その前にローカルで以下のコマンドをたたき、
インストールしたいライブラリをまとめておく。

pip freeze > requirements.txt

githubからDjangoアプリをクローンしてくる。

cd ~
git clone git@github.com:[アカウント名]/[リポジトリ名].git

ライブラリのインストールとコードの修正

必要なライブラリをインストールする

cd リポジトリ名
pip install -r requirements.txt

mysqlclientをinstallしようとするとエラーが出ることがある。
その場合は以下のコマンドを打ってから、mysqlclientをinstallする。

sudo pip3 install mysql-devel
sudo pip3 install --upgrade pip setuptools
sudo yum install python3-devel
sudo yum install gcc

envファイルを使用している場合は作成する。
内容は各々のものを書き込む。DBの設定など。

sudo vi .env

settings.pyのALLOWED_HOSTSにサーバーのパブリックIPを入れる。
また、STATIC_ROOTを追加しておく。

sudo vi settings.py
settings.py
ALLOWED_HOSTS = [*.*.*.*]
STATIC_ROOT = os.path.join(BASE_DIR,'static')

mysqlの設定

以下のコマンドでmysqlをインストールする

# MySQL yumリポジトリからMySQL8.0のRPMパッケージをダウンロード
sudo yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm 
# MySQLのGPGキーの有効期限切れの可能性があるため、新しいGPGキーをインポートする
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
# MySQLのインストール
sudo yum install --enablerepo=mysql80-community mysql-community-server -y
# MySQLバージョン確認
mysql --version
# MySQLの起動
sudo systemctl start mysqld.service
# 起動確認
systemctl status mysqld.service
# サーバー起動時にMySQLを自動起動するよう設定
sudo systemctl enable mysqld.service

以下のコマンドで、mysqlのユーザーとDBを作成する。

# 初期パスワードを確認する
sudo cat /var/log/mysqld.log
# MySQLへ接続する(上記で確認したパスワードを入力する)
mysql -u root -p
# パスワードを変更する(変更しないと他のエラーになる)
ALTER USER 'root'@'localhost' IDENTIFIED BY '新パスワード';
# DBを作成する
CREATE DATABASE db_name;
# ユーザーを作成する(ユーザ名とパスワードは自由に設定してください)
CREATE USER 'myapp'@'%' IDENTIFIED BY 'password';
# 作成したユーザーにすべての操作権限を付与
GRANT ALL ON db_name.* TO 'myapp'@'%';
# 設定の反映
FLUSH PRIVILEGES;

マイグレーションとマイグレートを行う。

python3 manage.py makemigrations
python3 manage.py migrate

ここで、mysqlの認証方法の違いでエラーが出ることがある。
mysql8からは認証方法が変更されているらしいので、今回使うDBにも変更をかけてあげてからマイグレーションとマイグレートをするとうまくいく。

mysql
alter user 'user_name'@'localhost' identified WITH mysql_native_password by 'password';

一度gunicornを立ち上げて見てみる。

以下のコマンドを打ち、パブリックIP:8000にアクセスし、画面が表示されればOK。
アプリによってはCSSは反映されてなくて良い。

sudo gunicorn リポジトリ名.wsgi --bind=0.0.0.0:8000

フロント周りのビルドを行う

nvmをインストールしてnodejsとnpmを使用できるようにする。
ここで注意が必要なのは、nodeのversionは16以下にしないと動かない。
(AWSが今は最新のversionに対応していないらしい。)

# nvmをインストールする
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
# nvmを有効にする
. ~/.nvm/nvm.sh
# nodejsをインストールする
nvm install node
# version16をインストールする
nvm install 16
# version16を使うように設定する
nvm use 16

package.jsonのあるフォルダまで行き、以下を実行する。

npm install
# 各自で設定したビルドコマンドを実行する
npm run build

ビルドをする際に、ディレクトリへのアクセス権限が無くてエラーになった場合、以下のコマンドでユーザーに権限を付与するとうまくいく。

sudo chown -R user_name ディレクトリへのパス

gunicornの設定を行う

設定ファイルの作成・編集

以下のコマンドで設定ファイルを作成(編集)する。

sudo vi /etc/systemd/system/gunicorn.service
sudo vi /etc/systemd/system/gunicorn.socket

gunicorn.serviceの中身

gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
Type=notify
# the specific user that our service will run as
# ここのユーザ名とグループ名はデーモンを実行するユーザを入れる。
# 特に何も考えていなければec2-userにする。
User=ec2-user
Group=ec2-user
# another option for an even more restricted service is
# DynamicUser=yes
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
RuntimeDirectory=gunicorn
# Djangoプロジェクトのパスを入れる
WorkingDirectory=/home/ec2-user/mysite
# gunicornの実行ファイルのあるパスと、プロジェクトのアプリの名前.wsgi
ExecStart=/usr/local/bin/gunicorn mysite_app_name.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target

gunicorn.socketの中身

gunicorn.socket
[Unit]
Description=gunicorn socket

[Socket]
# sockファイルを作る場所を入れる。基本はdjangoプロジェクトのパスを入れておく。
ListenStream=/home/ec2-user/mysite/mysite_app_name.sock
# Our service won't need permissions for the socket, since it
# inherits the file descriptor by socket activation
# only the nginx daemon will need access to the socket
# gunicorn.serviceと同じユーザを入れる
SocketUser=ec2-user
# Optionally restrict the socket permissions even more.
# SocketMode=600

[Install]
WantedBy=sockets.target

gunicornの起動

sudo systemctl start gunicorn.service
sudo systemctl enable gunicorn
# ちゃんとプロセスが動いていることを確認する。
sudo systemctl status gunicorn

nginxの設定を行う

まずは動くかどうかのテスト

nginxを起動して、パブリックIPにアクセスしてみる。
nginxの画面が表示されればOK。nginxを終了する。

# nginxを起動する
systemctl start nginx
# nginxを終了する
systemctl stop nginx

nginxの設定ファイルを作成・編集

以下のコマンドでnginx.confを編集する。

sudo vi /etc/nginx/nginx.conf

nginx.confの中身

nginx.conf
# 全文は多すぎるので省略。userをnginxからec2-userなどのサービスを動かすユーザーへ変える。
...
user ec2-user;
...
# httpブロック内などに、この一行があるか確認する。書いてあればOK。
include /etc/nginx/conf.d/*.conf;
...

以下のコマンドで/etc/nginx/conf.d/mysite.confを作成・編集する。
これは新規作成であり、ファイル名はなんでも良い。

sudo vi /etc/nginx/conf.d/mysite.conf

mysite.confの中身

mysite.conf
server {
    listen  80;
    # ドメインあるいはIPアドレスを設定する
    server_name     *.*.*.*;

    # djangoの静的ファイルの置き場所を指定する。
    location /static {
        alias /home/ec2-user/mysite/static;
    }

    # djangoのadmin用の静的ファイルの置き場所を指定する。
    location /static/admin {
        alias /home/ec2-user/mysite/static/admin;
    }

    # gunicorn起動時に作成されるsockファイルの場所を指定する。
    location / {
        proxy_pass http://unix:/home/ec2-user/mysite/mysite_app_name.sock;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

}

nginxを起動する

以下のコマンドでnginxを起動する。

sudo systemctl start nginx
# すでに起動していた場合はsudo systemctl restart nginx
# プロセスが適切に動いていることを確認する
sudo systemctl status nginx

動いているかブラウザで確認する

パブリックIPにアクセスしてしっかり動いているかを確認する。
CSSが当たっていない場合、mysite.confの「location /static」のパスが間違っている可能性がある。
正しくブラウザで動いていたら完了。

Discussion