0
2

【2024/8 簡単ガイド】NginxとGunicornを使って、DjangoのWEBアプリをAWS EC2にデプロイする方法

Posted at

最近、研究室内専用の就活プラットフォームがあればなと思い、とあるサイトを作成しました。

Djangoを用いて開発し、AWSのEC2にデプロイしたんですが、その方法を書いていきます。

誤記等ありましたら、お気軽に言っていただけますと幸いです!

構想

以下の構想でデプロイを行いました。
qiiia.png

前提

2つあります。

  • github上にデプロイしたいWebアプリがあること
  • AWS用語の基礎知識があること
    (下記が分かっていればOK)
    • Amazon VPC
    • AZ
    • サブネット
    • ルートテーブル
    • インターネットゲートウェイ
    • セキュリティグループ

↓説明を載せておくので、参考にしてください!

用語 説明
Amazon VPC Amazon Virtual Private Cloud(Amazon VPC)とよびます。AWS上に構築するプライベートネットワーク空間のことです。AWS内で複数作成でき、用途ごとに接続先を設定することが可能です。
アベイラビリティゾーン(AZ) AWSが世界各地に配置しているリージョン内にある、1つ以上のデータセンターで構築された小さな区分けのことです。AZ間は低遅延専用線で接続されています。
サブネット ネットワークを分割して作った小さなネットワークのことです。一般的なサブネットの意味と変わりません。AWSの場合、VPC内にサブネットを構成して利用するのが基本です。
ルートテーブル サブネット毎の通信設定ルールです。設定を行うことで、システム内の通信経路を制御し、安全性を確保することができます。
インターネットゲートウェイ VPCとインターネット間の通信を可能にするゲートウェイです。
IAMロール AWSで提供されているサービスの中で、ユーザが実際に操作できる対象(Amazon EC2であればEC2インスタンス)などに操作権限(IAMポリシー)を付与する仕組みのことです。
セキュリティグループ インスタンス単位で通信の許可/禁止を設定できるファイアウォールです。そのため、ルートテーブルより細かな通信制御が可能です。

環境

  • Windows
  • Python 3.12.3
  • Django 5.1
  • SQLite3 3.45.1
  • nginx 1.24.0
  • gunicorn 23.0.0

大まかな手順

  1. EC2を作成して、SSH接続を行う
  2. 仮想環境に入り、デプロイしたいプログラムをgit clone
  3. settings.pyのALLOWED_HOSTSにパブリックIPを記述
  4. migrateできるか確認
  5. セキュリティグループのインバウンドルールを編集し、ポート8000番のルールを追加
  6. python3 manage.py runserver 0.0.0.0:8000を実行
  7. http:Elastic IP:8000で正常表示されるか確認
    1. ここまででデプロイだけは完了
  8. nginxおよびgnicornの設定
  9. アクセス確認

1.AWS EC2インスタンスの作成および設定

では、AWSコンソールにアクセスし、EC2インスタンスを作成します。

設定内容

  1. インスタンスの種類: t2.micro(無料利用枠に該当)
  2. AMI(Amazon Machine Image): Ubuntu 20.04 LTS
  3. ストレージ: デフォルトの8GBで十分です。
  4. セキュリティグループ: HTTP(ポート80)とSSH(ポート22)を許可するルールを設定

作成が完了したら、EC2インスタンスにSSHで接続します。

作成したEC2インスタンスを選択後、下記画像の「接続」というボタンを押してください。

image.png

そしたら、下記のようなメニューが出てくると思います。
「SSHクライアント」を押してください。(画像では既に押しています)
image.png

そしたら、下部に「例:」というものがあるはずです。それを下記のように実行してください。

$ chmod 400 鍵の名前
$ ssh -i "鍵の名前" ubuntu@ec2-52-199-26-236.ap-northeast-1.compute.amazonaws.com

Are you sure you want to continue connecting (yes/no/[fingerprint])?ときかれたら、yesと入力してください。

これで、EC2の中に入れました。

2.EC2上でDjangoアプリをセットアップ

EC2に接続したら、まずシステムのアップデートを行います。

$ sudo apt-get update
$ sudo apt-get upgrade

次に、必要なパッケージをインストールします。

$ sudo apt-get install python3-pip python3-dev nginx

3.仮想環境に入る

ここからは仮想環境で少し作業をします。

$ python3 -m venv myenv
$ source myenv/bin/activate

なお、仮想環境を出るときは下記コマンドで出れます。

$ deactivate

4.GitHubからコードをクローンし、環境を整える

2021年8月からGithubではセキュリティー強化のために、httpsで認証する場合はトークンベースの認証となりました。

アクセストークンの取得方法は下記記事を参考にしてください。
https://qiita.com/LaP1s/items/69409c6bf08f8c7bca48

$ git clone https://github.com/あなたのgithub垢アカウント名/リポジトリ名.git
$ cd リポジトリ名
$ pip3 install -r requirements.txt

5.settings.pyのALLOWED_HOSTSにパブリックIPを記述

settings.pyがあるディレクトリに入り、下記コマンドで編集します。

$ vim settings.py
settings.py
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')

ここである疑問が生まれるかもしれません。

「開発サーバーの時はALLOWED_HOSTSを指定しなくても動いたのになぜ指定するのか?」

なぜALLOWED_HOSTSの設定が必要なのか

結論から言うと、
開発環境では、DEBUGがTrueに設定されていたからです。

DjangoはALLOWED_HOSTSが空であっても、DEBUGがTrueになっている場合、localhostや127.0.0.1からのリクエストを許可します。

このため、開発サーバーをローカルで使用する場合、特にALLOWED_HOSTSを指定する必要がなかったんです。

(補足として開発中でも、ローカルホスト以外のIPアドレスやドメインでアクセスする場合は、ALLOWED_HOSTSに追加する必要があります。)

しかし、本番環境ではDEBUGをFalseに設定します。この場合、ALLOWED_HOSTSが空であると、すべてのリクエストが拒否されてしまいます。

DEBUGは詳細なデバック情報を表示します。そのため本番環境でTrueにしてしまうと、悪意のあるユーザーにアプリケーションの内部情報を漏らす危険性があるため、Falseにします。

6.migrateできるか確認

manage.pyのある階層に移動し、migrateを実行する。

$ python3 manage.py migrate

実行できたら大丈夫です!

7.開発サーバーでの確認

開発サーバーはポート8000番を使用するので、EC2インスタンスのセキュリティグループのインバウンドルールを編集します。

下記画像のようにしてください!
image.png

下記コマンドを実行し、「http://パブリックIPアドレス:8000」でアクセスしてください。

$ python3 manage.py runserver 0.0.0.0:8000

無事、所望の画面が出れば成功です!

8.gnicornの設定

仮想環境から抜けて作業します。

$ deactivate

GunicornはWSGIサーバーとして、Djangoアプリを処理します。まず、サービスファイルを作成します。

下記のコマンドを打ってgunicornの設定を行っていきましょう。

$ sudo vim /etc/systemd/system/gunicorn.service

以下のように記述します。
日本語の部分は適宜ご自身の環境の合わせて記述してください。

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/リポジトリの名前
ExecStart=/home/ubuntu/仮想環境の名前/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/リポジトリの名前と同じ/Djangoのプロジェクト名.sock Djangoのプロジェクト名.wsgi:application

[Install]
WantedBy=multi-user.target

Gunicornを起動し、自動起動するように設定します。

$ sudo systemctl start gunicorn
$ sudo systemctl enable gunicorn

9.Nginxの設定

Nginxをリバースプロキシとして設定します。設定ファイルを作成します。

$ sudo vim /etc/nginx/sites-available/myproject

以下のように記述します。
日本語の部分は適宜ご自身の環境の合わせて記述してください。

server {
        listen 80;
        server_name パブリックIP;

        location = /favicon.ico {access_log off; log_not_found off;}
        location /static/ {
                root /home/ubuntu/リポジトリの名前と同じ;
        }

        location / {
                include proxy_params;
                proxy_pass http://unix:/home/ubuntu/リポジトリの名前と同じ/プロジェクト名.sock;
        }
}

シンボリックリンクを作成してNginxを再起動します。

$ sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
$ sudo systemctl restart nginx

10.セキュリティグループ設定

HTTPのインバウンドルールを追加します。
具体的には、下記の画像を参考にしてください。
image.png

そのあとgunicornを再起動します。

$ sudo systemctl restart gunicorn

11.デプロイの確認とトラブルシューティング

NginxとGunicornが正しく動作しているか確認するため、ブラウザでhttp://パブリックIPにアクセスします。アプリが表示されればデプロイ成功です。

もし動作しない場合、以下2点を確認してください。

  • Nginxのエラーログ: /var/log/nginx/error.log
  • Gunicornのエラーログ: サービスファイルで設定した--access-logfile -の出力先

12.ソケット通信がうまくいかない…

もしソケット通信がうまく動作しない場合、Gunicornをソケットではなく、ポート8000でバインドし、Nginxがそのポートにリクエストをプロキシする設定に切り替えることができます。

Gunicornをポート8000でバインドする

まず、/etc/systemd/system/gunicorn.serviceの設定を修正します。

以下のようにExecStartの行を修正します:

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/yourrepository
ExecStart=/usr/local/bin/gunicorn --access-logfile - --workers 3 --bind 0.0.0.0:8000 myproject.wsgi:application

[Install]
WantedBy=multi-user.target

この設定により、Gunicornが直接ポート8000でリクエストを受け付けるようになります。

Nginxの設定を修正する

次に、Nginxの設定を修正し、プロキシ先をソケットファイルからポート8000に変更します。

$ sudo vim /etc/nginx/sites-available/myproject

以下のようにlocation /セクションを修正します:

server {
    listen 80;
    server_name your-ec2-public-ip;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/ubuntu/yourrepository;
    }

    location / {
        include proxy_params;
        proxy_pass http://127.0.0.1:8000;
    }
}

NginxとGunicornの再起動

設定変更後、NginxとGunicornを再起動して、新しい設定を反映させます。

$ sudo systemctl restart gunicorn
$ sudo systemctl restart nginx

動作確認

再度、ブラウザでhttp://パブリックIP/にアクセスし、アプリが正しく表示されるか確認します。
この方法では、ソケット通信の問題を回避し、Gunicornがポート8000で直接リクエストを受け取るため、トラブルシューティングに役立ちます。

お金を無駄にしないために

下記3点は使い終わったら必ずやっておきましょう!

  • EC2インスタンスを「終了」させる
  • セキュリティグループの削除
  • Elastic IPの解放

まとめ

以上で今回の解説を終わります!

長い記事を最後まで読んでいただきありがとうございました!

訂正箇所などあれば、お気軽にお声がけいただけますと幸いです。よろしくお願いいたします。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2