Django_本番環境構築②_EC2で起動したアプリケーションにHTTPS通信する #365
前回からの続きです。
ディレクトリ構成などの前提情報は良ければ上記をご参照ください。
前回までの構成を活かし、アプリケーションをEC2上で起動させてみたいと思います。
前提として、AWSのEC2インスタンスが1つ立ち上げています。仮にもインターネット環境でのテストなので、本来はVPNなどを設定して実施するのが望ましいとは思います。ただVPNは追い追いやってみようと思っているところなので、今回はセキュリティグループで最低限の制御だけかけて実施することにしました。
本日のポイントは大きく2つです。
Nginxの設定
DjangoのCSRF検証の設定
それではまとめていきます。
はじめに
今回なぜHTTPS通信で試してみようと思ったかについて語っておきます。もちろん本番運用ではHTTPSが当たり前だからでもあるのですが、その前に、HTTP通信ではあるエラーに当たったからです。
nginxとgunicornでアプリケーションを起動した場合、EC2では、HTTP通信に対して以下のエラーが出ました。
`The Cross-Origin-Opener-Policy header has been ignored,
because the URL's origin was untrustworthy.
It was defined either in the final response or a redirect.
Please deliver the response using the HTTPS protocol.
You can also use the 'localhost' origin instead`
このエラーは、Cross-Origin-Opener-Policy (COOP) ヘッダが信頼できないオリジン(URLのドメイン部分)から送信されたため、無視されていることを示しています。
結果としてCSSやJavaScriptが読み込まれませんでした。
この解決策としてHTTPSを使うことを選択しました。
localhostでもこのエラーは出ないみたいなのですが、本番環境の構築に向けて動いていたので。
また、COOPはResponseヘッダーに記述されており、EC2インスタンスの設定をいじる手もあるのかなとは思います。ただこれらはHTTPヘッダー関連として別途まとめて、別項目として理解を深めようと思います。
それでは各設定を見ていきます。
Nginxの設定
冒頭の過去記事でご紹介したファイルをアップデートしています。
[nginx.conf]
user nginx;
events {}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
upstream django_app {
server my_application_prod:80;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://my_application_prod:8000;
proxy_set_header Host $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;
}
}
server {
listen 443 ssl;
server_name localhost_443;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://my_application_prod:8000;
proxy_set_header Host $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;
}
location /static/ {
alias /var/www/my_application/staticfiles/;
}
}
}
HTTPS用の443ポートをリッスンするserverを立てています。HTTP用と異なる部分は以下です。
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
HTTPS通信を実現するにはSSLが必要ですが、これは本来は認証局に申請して貰わなければなりません。今回はサクッと試したいだけなので、「自己署名証明書」という方法で設定しています。
この設定は開発段階のみで、本番運用する場合はきちんと認証局に発行してもらう必要があります(自己署名だと「信頼できないサイト」とブラウザからも扱われます)。
自己署名証明書の作成方法は簡単で、以下のコマンドで作成できます。
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
ただnginxだと鍵ファイルにパスワードがかかっていると扱えないため、パスワードを外しておきます(これは危険な行為でもあるのでアクセス制限など十分に注意してください)。
openssl rsa -in key.pem -out key_nopass.pem
DjangoのCSRF検証の設定
これはDjango4.0以上で必要になる対応です。Django4.0以上は、settings.pyで「CSRF_TRUSTED_ORIGINS」にオリジンを指定しないと、POSTリクエスト時に403Forbiddenになります。つまり、CSRF検証でのエラーとして検出されます。
以下のように設定すればOKです。
ALLOWED_HOSTS = [
'xx.xxx.xxx.xxx', # IPアドレスを許可
'yourdomain.com', # ドメイン名を許可
]
# CSRF検証のため信頼できるオリジンを指定(本番環境ではドメイン名を指定する)
CSRF_TRUSTED_ORIGINS = [
'https://IPアドレスかドメイン名',
]
上記のような設定で、EC2上でHTTPS通信を実現し、アプリケーションのCSSやJavaScriptも無事に反映されるようになりました。
ここまでお読みいただきありがとうございました!