この記事は、AmazonLinux2,Python3.7,Nginx,Gunicorn,PostgreSQLを利用して、Djangoプロジェクトの本番環境構築の方法を紹介します。
独自ドメインでの表示設定、https化の方法についても解説していきます。
◆動作検証環境
・aws
・OS:AmazonLinux2
・Python:3.7.9
・Django:3.1.1
・Nginx:1
・Gunicorn:20.1.0
・PostgrSQL:11
・psycopg2:2.7.7
インスタンスへ接続(ログイン)
ローカル環境ので使用する秘密鍵の設定
EC2ダッシュボードで接続の方法を確認します。
対象のインスタンスが選択されている事を確認して、[接続]をクリックします。
接続方法が表示されます(スタンドアロンSSHクライアント)。
今回は、Macを利用する方法で解説します。
EC2インスタンスを作成する際に、秘密鍵を作成した際は、ダウンロードフォルダにキーがありますので、まずは.sshフォルダを作成し、権限を設定します。
1 2 3 | $ mkdir ~/.ssh |
1 2 3 | $ chmod 700 ~/.ssh |
EC2インスタンス作成の際にダウンロードした秘密鍵をさきほど作成した.sshフォルダに移動します。
対象のディレクトリへ移動して秘密鍵の権限を変更します。
1 2 3 | chmod 400 ec2_key.pem |
ここまで設定できたらSSH接続でインスタンスへログインします。
EC2ダッシュボードでの表示を参考に下記のコマンドを実行します。
1 2 3 | ssh -i ~/.ssh/ec2.pem ec2-user@ec2-000-00-00-000.us-east-2.compute.amazonaws.com |
※AmazonLinuxの初期ユーザーは、ec2-user , Ubuntuの初期ユーザーはubuntu となります。
EC2インスタンス(リモートサーバー)の初期設定
linuxの初期設定
1 2 3 | $ sudo yum update -y |
1 2 3 | $ sudo timedatectl set-timezone Asia/Tokyo |
1 2 3 | $ date |
1 2 3 | $ sudo localectl set-locale LANG=ja_JP.UTF-8 |
1 2 3 | $ localectl status |
新規ユーザーの作成と設定
セキュリティー強化のため、EC2の設定で準備されているデフォルトユーザーの代わりとなる、新規のユーザーを作成します。
ユーザーの作成
1 2 3 | $ sudo useradd NEWUSER |
ユーザーを作成すると、/home/の中に新ユーザー名のディレクトリが作成されるので、ec2-userディレクトリに設置されていたディレクトリやファイルを移動する。
1 2 3 | $ sudo cp -arp /home/ec2-user/.ssh /home/NEWUSER |
1 2 3 | $ sudo chown -R NEWUSER /home/NEWUSER/.ssh |
1 2 3 | $ sudo visudo -f /etc/sudoers.d/90-cloud-init-users |
1 2 3 4 5 6 7 8 | # User rules for ec2-user ec2-user ALL=(ALL) NOPASSWD:ALL ↓ # User rules for ec2-user ec2-user ALL=(ALL) NOPASSWD:ALL NEWUSER ALL=(ALL) NOPASSWD:ALL |
1 2 3 | $ exit |
新規ユーザーでのログインと、root権限の確認
新たに作成したユーザーでログインを試します。
1 2 3 | $ ssh -i ~/.ssh/ec2.pem NEWUSER@ec2-000-00-00-000.us-east-2.compute.amazonaws.com |
ログインできる事が確認できたら、root権限を利用できるか確認します。
1 2 3 | $ sudo su |
以下のように表示が変われば確認OKです。
$ →#
デフォルトユーザーの削除
以上の確認ができたらデフォルトユーザーを削除し、関係ファイルを編集します。
1 2 3 | $ sudo userdel -r ec2-user |
90-cloud-init-usersファイルの編集
1 2 3 | $ sudo visudo -f /etc/sudoers.d/90-cloud-init-users |
1 2 3 4 5 6 7 8 | # User rules for ec2-user ec2-user ALL=(ALL) NOPASSWD:ALL NEWUSER ALL=(ALL) NOPASSWD:ALL ↓ # User rules for ec2-user NEWUSER ALL=(ALL) NOPASSWD:ALL |
ファイヤーウォールの設定
firewalldのインストール
1 2 3 | $ sudo yum install firewalld |
ファイヤーウォールのスタート
1 2 3 | $ sudo systemctl start firewalld |
http(80番)の追加
1 2 3 | $ sudo firewall-cmd --add-service=http --zone=public --permanent |
https(443番)の追加
1 2 3 | $ sudo firewall-cmd --add-service=https --zone=public --permanent |
8000番の追加(Djangoの内蔵サーバー起動時に使用)
1 2 3 | $ sudo firewall-cmd --zone=public --add-port=8000/tcp --permanent |
設定を反映させる。
1 2 3 | $ sudo firewall-cmd --reload |
1 2 3 | $ sudo firewall-cmd --list-all |
1 2 3 | $ sudo systemctl enable firewalld |
1 2 3 | $ sudo systemctl restart firewalld |
1 2 3 | $ sudo systemctl status firewalld |
Postglesqlの設定
Postglesqlのインストールと初期設定
1 2 3 | $ amazon-linux-extras list | grep postgresql |
1 2 3 4 5 | 5 postgresql9.6 available \ 6 postgresql10 available [ =10 =stable ] 41 postgresql11 available [ =11 =stable ] |
1 2 3 | $ sudo amazon-linux-extras install postgresql11 |
1 2 3 | $ psql --version |
1 2 3 | $ sudo yum install postgresql-server |
1 2 3 | $ sudo postgresql-setup initdb |
1 2 3 | $ sudo systemctl enable postgresql |
1 2 3 | $ sudo systemctl start postgresql |
Postglesqlデータベースの作成
1 2 3 | $ sudo -u postgres -i psql |
1 2 3 | # CREATE DATABASE your_database; |
1 2 3 | # CREATE USER your_user_name WITH PASSWORD 'yourpassword'; |
1 2 3 | # ALTER ROLE your_user_name SET client_encoding TO 'utf8'; |
1 2 3 | # ALTER ROLE your_user_name SET timezone TO 'UTC+9'; |
1 2 3 | # GRANT ALL PRIVILEGES ON DATABASE your_database TO your_user_name; |
1 2 3 | # \q |
1 2 3 | $ ps aux |
1 2 3 4 5 6 7 8 9 | USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 1.2 168408 5960 ? Ss 10月21 0:32 /sbin/init root 2 0.0 0.0 0 0 ? S 10月21 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? I< 10月21 0:00 [rcu_gp] ... ... ... |
ポスグレのリモート接続(コンフィグファイル)設定
1 2 3 | $ sudo su |
1 2 3 | # cd /var/lib/pgsql/data |
1 2 3 | # sudo vim pg_hba.conf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # "local" is for Unix domain socket connections only local all all password #(peerから変更) # IPv4 local connections: host all all 127.0.0.1/32 ident host all all 0.0.0.0/0 ident #行追加 # IPv6 local connections: host all all ::1/128 ident # Allow replication connections from localhost, by a user with the # replication privilege. local replication all password #(peerから変更) host replication all 127.0.0.1/32 ident host replication all ::1/128 ident |
postgresql.conf の編集
1 2 3 | # listen_addresses = ‘localhost’ => listen_addresses = ‘*’ |
1 2 3 | $ sudo systemctl restart postgresql |
Virtualenvの仮想環境の構築
今回利用するAmazonLinuxはすでにpython3がインストールされているので、新たにインストールする必要はありません。
1 2 3 | $ python3 -m venv venv |
仮想環境の実行
1 2 3 | $ source venv/bin/activate |
仮想環境の有効時はターミナルなる表示が下記のようになります。
1 2 3 | (venv) username@xxx-xxx-xxxxx:~$ |
仮想環境の中にdjangoとgunicornとpsycopg2(pythonとpostgresqlをつなげるライブラリー)をインストール
1 2 3 | (venv) $ pip3 install django gunicorn psycopg2-binary |
Djangoプロジェクトのデプロイ
仮のDjangoプロジェクトの設置
本番環境の最低限の環境構築の準備ができましたので、本番環境のサーバーにDjangoプロジェクトを設置します。
仮想環境の実行を行います。
1 2 3 | $ source venv/bin/activate |
プロジェクトを作成するディレクトリに移動して、スタートアッププロジェクトを作成します。
1 2 3 | (venv)$ django-admin startproject project_name |
今回はGitHubのリポジトリを利用する方法を紹介します。
gitをインストールします。
1 2 3 | $ sudo yum install git |
プロジェクトを設置したディレクトリへ移動してクローンします。
$ git clone <https:xxxx@xxxxxx.xxxx.xxxx.xxxxxxx.>
settings.pyを編集します。
自分のリモートサーバーのホストを入力します。
1 2 3 | ALLOWED_HOSTS = ['xxx.xxx.xxx.xxx'] |
新規でプロジェクトを作成した場合は、さきほど行ったpostgresqlの設定に合わせて、データベースの設定も変更します。
1 2 3 4 5 6 7 8 | DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } |
上記の設定を下記の内容に変更します。
1 2 3 4 5 6 7 8 9 10 11 12 | DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'your_database', 'USER': 'your_user_name', 'PASSWORD': 'yourpassword', 'HOST': '', 'PORT': '', } } |
modelクラスの設定を反映させるために、ベースディレクトリでマイグレーションを行います。
※ベースディレクトリ = manage.pyがあるディレクトリ
1 2 3 | $ python3 manage.py migrate |
次に以下のように0.0.0.0:8000 と指定して起動します。
1 2 3 | $ python3 manage.py runserver 0.0.0.0:8000 |
それぞれのリモートサーバーのIPアドレスの8000番ポートを指定してブラウザで確認します。
1 2 3 | xxx.xxx.xxx.xxx:8000/ |
Djangoのウェルカムページが確認できればOKです。
Gunicornの設定
Djangoの内蔵サーバーでのサイト表示が確認できましたので、次にGunicornのアプリケーションサーバーを起動してサイトの表示を確かめます。
Gunicornの起動
仮想環境を有効にして下記のコマンドを実行します。
projectアプリケーションを含むディレクトリ(manage.pyコマンドを実行する時のディレクトリ)に移動して下記のコマンドを実行します。
1 2 3 | (venv) $ gunicorn --bind 127.0.0.1:8000 project.wsgi -D |
project.wsgi とする事で、projectアプリケーション内のwsgi.pyを参照させています。
wsgiファイル名はそれぞれのプロジェクトに応じて変更します。
127.0.0.1:8000と指定する事で、Djangoにバインド(紐付ける)させています。
-Dのオプションをつける事で、バックグラウンドでGunicornを起動させます。
Gunicornの起動確認
以下のコマンドを実行するとプロセスが立ち上がっているか確認できます。
1 2 3 | $ ps ax | grep gunicorn |
以下のように表示されればOKです。
1 2 3 4 5 | 3597 ? S 0:09 /home/ec2-user/venv/bin/python3 /home/ec2-user/venv/bin/gunicorn --bind 127.0.0.1:8000 project.wsgi -D 3600 ? S 0:02 /home/ec2-user/venv/bin/python3 /home/ec2-user/venv/bin/gunicorn --bind 127.0.0.1:8000 project.wsgi -D 11471 pts/0 S+ 0:00 grep --color=auto gunicorn |
起動後はブラウザにてサイトが表示されるか確認します。
内蔵サーバーの時のように以下の方法で、ブラウザにアクセスし表示を確かめます。
次に以下のように0.0.0.0:8000 と指定して起動します。
1 2 3 | $ python3 manage.py runserver 0.0.0.0:8000 |
それぞれのリモートサーバーのIPアドレスの8000番ポートを指定してブラウザで確認します。
1 2 3 | xxx.xxx.xxx.xxx:8000/ |
サイトが表示されればOKです。
確認後、Djangoのサーバーは停止しますが、Gunicornはバックグラウンドでの動作を継続させます。
Gunicornの停止:
1 2 3 | $ sudo pkill gunicorn |
Gunicornを再起動する場合は、一度停止してから再度、バックグラウンドモードで起動します。
OSが再起動する場合は、もう一度Gunicornも起動する必要があります。
Nginxの設定
静的なファイルに関係する動作はNginxに担当させ、負荷のかかる動的な動作はNginxからgunicornを呼び出し対応させるます。
この設定によって、ユーザーのリクエストの種類によって無駄の内サーバー動作を行えるようになります。
Nginxのインストール
nginxをインストールすとために、利用可能なバージョンを確認します。
1 2 3 | $ amazon-linux-extras list | grep nginx |
今回は以下のように表示されます。
1 2 3 | 38 nginx1 available [ =stable ] |
この表示を参考にバージョンを指定してインストールを行います。
1 2 3 | $ sudo amazon-linux-extras install nginx1 |
Nginxの起動設定
自動起動の設定
1 2 3 | $ sudo systemctl enable nginx.service |
起動
1 2 3 | $ sudo systemctl start nginx.service |
起動状況の確認
1 2 3 | $ sudo systemctl status nginx.service |
1 2 3 | Acrive : active(running) |
というように表示されればOK
ブラウザでの起動確認
対象のサーバーのIPアドレスを入力して、ブラウザで起動の確認を行います。
以下のようにNginxのウェルカムページが表示されればOK
Nginxのコンフィグファイルの編集
Nginxが起動している事が確認できたので、現在のサーバーに応じた設定を行い、またGunicornと連携できるように設定を行います。
configファイルの編集
1 2 3 | $ sudo vim /etc/nginx/nginx.conf |
server情報が記載されている箇所を以下のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | listen 80; listen [::]:80; server_name <Elastic ip>; root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location / { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:8000; } |
作成したコンフィグファイルの検証
1 2 3 | $ sudo nginx -t |
下記のように表示されればOKです。
*エラーの表示がある場合は対応します。
1 2 3 4 | nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful |
Nginxのリスタート
1 2 3 | $ sudo systemctl restart nginx.service |
Nginxを利用してのサイト表示確認
これまでのGunicornとNginxの設定を確認するために、ブラウザで表示確認を行います。
ブラウザにアクセス(ポート番号の指定は無し)してプロジェクトの表示を確認します。
サイトの表示が確認できればOKです。
今後は8000番ポートは使用しないので、ファイヤーウォールを閉じます
1 2 3 | $ sudo firewall-cmd --zone=public --remove-port=8000/tcp --permanent |
独自ドメイン・SSL化とリダイレクト設定
今までの設定で、IPアドレスの指定でサイトへアクセスできるようになりました。
ここからは独自ドメインの設定と、SSLとリダイレクトの設定を行います。
EC2側の設定は設定は以下のようになります。
独自ドメインのアクセス許可
Django/Settings.pyの設定
1 2 3 | ALLOWED_HOSTS = ['yoursite.com’] |
Nginxコンフィグファイルの編集
Webサーバーのエントリーファイルがあるディレクトリへ移動し、編集します。
1 2 3 | $ sodo vim /etc/nginx/nginx.conf |
1 2 3 4 5 | server_name <Elastip ip>; ↓ server_name yoursite.com; |
Nginxのリスタート
1 2 3 | $ sudo systemctl restart nginx.service |
独自ドメイン使用時のEC2の設定
今回はLet’s Encryptで提供されているcerbotツールを利用してHTTPS化を行います。
まず、EC2のホームディレクトリにcerbotのファイルを設置します。
Gitのcloneコマンドを利用しますので、Gitのインストールがまだの場合は行います。
1 2 3 | $ sudo yum install git |
ホームディレクトリである事を確認し、cerbotのパッケージをクローンします。
1 2 3 | $ git clone https://github.com/certbot/certbot |
この際、登録されているユーザー名とパスワードの入力が必要となります。
次にcerbotの実行で使用されるpython製のパッケージをインストールします。
1 2 3 | $ sudo yum -y install python-virtualenv |
HTTPS化のためのNginxコンフィグファイルの編集①
certbotの証明書と秘密鍵取得に備え下記のように編集します。
1 2 3 | $ sudo vim /etc/nginx/nginx.conf |
1 2 3 4 5 6 7 8 9 | server{ ... location /.well-known/acme-challeng { root /usr/share/nginx/html; } ... } |
設定変更を有効にするためリロード
1 2 3 | $ sudo systemctl reload nginx.service |
SSL証明書と秘密鍵の発行
以下のcertbotコマンドで証明書と秘密鍵を発行します。
1 2 3 | $ sudo ~/certbot/certbot-auto --no-bootstrap certonly --webroot -w /usr/share/nginx/html |
Skipping bootstrap because certbot-auto is deprecated on this system. ./certbot-auto has insecure permissions!
Nginxが起動している事を確かめ、以下のコマンドを実行します。
1 2 3 | $ sudo wget -r --no-parent -A 'epel-release-*.rpm' http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/ |
1 2 3 | $ sudo rpm -Uvh dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-*.rpm |
1 2 3 | $ sudo yum install certbot python2-certbot-nginx |
1 2 3 | $ sudo certbot --nginx |
対象となるドメイン名や、メールアドレスを設定する。
以下のようなメッセージが表示されれば、証明書と秘密鍵が指定のディレクトリに作成されています。
1 2 3 4 5 6 7 8 9 10 11 | IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/sample.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/sample.com/privkey.pem Your certificate will expire on 2021-09-20. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew"ex |
HTTPS化のためのNginxコンフィグファイルの編集②
certbotを利用するHTTPS化に対応するためにコンフィグファイルを以下のように編集(追加)します。
1 2 3 | $ sudo vim /etc/nginx/nginx.conf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | server { listen 80; listen [::]:80; server_name sample.com; return 301 https://$host$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; server_name sample.com; root /usr/share/nginx/html; ssl_certificate "/etc/letsencrypt/live/sample.com/fullchain.pem"; ssl_certificate_key "/etc/letsencrypt/live/sample.com/privkey.pem"; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location /.well-known/acme-challeng { root /usr/share/nginx/html; } location / { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:8000; } error_page 404 /404.html; location = /404.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } |
設定変更を有効にするためリロード
1 2 3 | $ sudo systemctl reload nginx.service |
独自ドメインでの表示確認
以下の方法でアクセスと表示を確認します。
https://sample.com → 表示されるか
http://sample.com → https://にリダイレクトされて表示されるか
SSL証明書の自動更新設定
Letsencriptの証明書は90日が有効期限となるため、継続して利用するには更新作業が必要となります。
自動で更新できるようにcronに更新のコマンドを設定します。
cron設定画面を開きます。
1 2 3 | $ sudo crontab -e |
以下のように編集します。
1 2 3 | 0 3 1 * * /home/username/certbot/certbot-auto renew -q --renew-hook "/usr/bin/systemctl reload nginx.service" |
-q オプションでエラーメッセージ以外を非表示にしています
–renew-hook オプションで更新のコマンドを実施後Nginxのリロードを行うようにしています。
static、mediaファイル表示の設定
開発環境ではstatic、mediaファイルはDjangoのプロジェクト内に作成していますが、本番環境ではNginxを利用して保存、表示を行うのでそちらの設定を行います。
settings.pyの編集
以下の内容になるよう編集、追加を行います。
1 2 3 4 5 6 7 8 9 10 11 12 | DEBUG = False STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) MEDIA_URL = '/media/' STATIC_ROOT = '/usr/share/nginx/html/static' MEDIA_ROOT = '/usr/share/nginx/html/media' |
※すでにstaticファイルを利用している場合は、ディレクトリ構造に合わせSTATICFILES_DIRSを指定します。
静的ファイルを配信ディレクトリに設置する
さきほどsettings.pyで指定した通りにリモートサーバー内にディレクトリを設置します。
リモートサーバーにSSH接続し、静的ファイルと、メディアファイルの作成と所有者の変更を行います。
1 2 3 | $ sudo mkdir -p /usr/share/nginx/html/static |
1 2 3 | $ sudo mkdir -p /usr/share/nginx/html/media |
1 2 3 | $ sudo chown username /usr/share/nginx/html/static |
1 2 3 | $ sudo chown username /usr/share/nginx/html/media |
リモートサーバー側にファイルを設置したので、Djangoアプリケーション内にある静的ファイルを、新たに作成したフォルダへ移します。
仮想環境に入り以下のコマンドを行います
1 2 3 | (venv) $ python3 manage.py collectstatic |
nginxへのコンフィグファイルの編集
server {…}の方へ以下のコードを追加します。
1 2 3 4 5 6 7 8 9 | location /static{ alias /usr/share/nginx/html/static; } location /media{ alias /usr/share/nginx/html/media; } |
変更後、gunicornとnginxの再起動を行いCSSが反映されて表示が確認できればOKです。
お疲れさまでした。ぺこり
以上、AmazonLinux2,Python3.7,Nginx,Gunicorn,PostgreSQLを利用して、Djangoプロジェクトの本番環境構築の方法、独自ドメインでの表示設定、https化について紹介しました。