Djangoデプロイチェックリスト
本番環境に安全に公開する
Djangoアプリケーションを本番環境にデプロイする手順とチェックリストを解説。Gunicorn、nginx連携、セキュリティ設定まで学べます。
こんな人向けの記事です
- Djangoアプリを本番環境に公開したい
- デプロイ時の設定漏れを防ぎたい
- Gunicorn+nginxの構成を理解したい
STEP 1デプロイ前の準備(DEBUG=False, ALLOWED_HOSTS)
Djangoアプリを本番環境に公開する前に、最低限変更しなければならない設定があります。これらを忘れると、セキュリティ上の深刻な問題を引き起こします。
DEBUG = False に設定する
DEBUG=Trueのまま本番運用すると、エラー発生時にスタックトレース、環境変数、URLパターンなどの内部情報がブラウザに表示されてしまいます。必ずFalseに設定してください。
import os
# 環境変数から読み込み、デフォルトはFalse
DEBUG = os.environ.get('DEBUG', 'False').lower() in ('true', '1', 'yes')
.envファイルにDEBUG=trueを書いたまま本番にデプロイしないでください。デフォルト値は必ずFalseにしましょう。
ALLOWED_HOSTS を設定する
ALLOWED_HOSTSはDjangoが受け付けるホスト名のリストです。DEBUG=Falseの場合、この設定が空だとすべてのリクエストが400 Bad Requestになります。
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
# 例: ALLOWED_HOSTS=example.com,www.example.com
ALLOWED_HOSTS = ['*']はすべてのホスト名を受け入れてしまうため、本番環境では使用しないでください。Hostヘッダー攻撃の原因になります。
SECRET_KEY を環境変数で管理する
SECRET_KEYはセッション、CSRFトークン、パスワードリセットなどの暗号処理に使われます。ソースコードに直書きせず、環境変数で管理してください。
SECRET_KEY = os.environ.get('SECRET_KEY')
if not SECRET_KEY:
raise ValueError('SECRET_KEY環境変数が設定されていません')
# 安全なキーの生成方法
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
本番用settings.pyの全体像
import os
DEBUG = False
SECRET_KEY = os.environ['SECRET_KEY']
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
# セキュリティ設定
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
STEP 2静的ファイルの収集(collectstatic)
Djangoの開発サーバーはDEBUG=Trueのときに自動で静的ファイルを配信しますが、本番環境ではcollectstaticコマンドで静的ファイルを1つのディレクトリに集約し、nginxなどのWebサーバーから配信する必要があります。
STATIC_ROOT を設定する
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# メディアファイル(ユーザーアップロード)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
collectstatic を実行する
# 静的ファイルを STATIC_ROOT に収集
python manage.py collectstatic --noinput
--noinputを付けると確認プロンプトなしで実行されます。CI/CDパイプラインやDockerビルド時に便利です。
WhiteNoise で簡易配信する方法
nginx無しで静的ファイルを配信したい場合は、WhiteNoiseミドルウェアが便利です。
pip install whitenoise
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # SecurityMiddlewareの直後に追加
# ...他のミドルウェア
]
# 静的ファイルの圧縮とキャッシュ
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
| 方式 | メリット | デメリット |
|---|---|---|
| nginx配信 | 高速、本番向き | nginx設定が必要 |
| WhiteNoise | 設定が簡単、Heroku等で便利 | パフォーマンスはnginxに劣る |
STEP 3データベースのマイグレーション
本番環境にデプロイする際は、データベースのスキーマを最新の状態に更新する必要があります。マイグレーションの手順を正しく理解しておきましょう。
マイグレーションの基本コマンド
# 適用されていないマイグレーションを確認
python manage.py showmigrations
# マイグレーションを実行
python manage.py migrate
マイグレーション前のチェック手順
# 1. バックアップ取得
pg_dump -U postgres mydb > backup_$(date +%Y%m%d_%H%M%S).sql
# 2. 適用予定のSQLを確認(ドライラン)
python manage.py sqlmigrate app_name 0001_initial
# 3. マイグレーション実行
python manage.py migrate
# 4. 結果確認
python manage.py showmigrations | grep "\[ \]"
sqlmigrateはマイグレーションが実行するSQLを表示するコマンドです。実際にDBを変更せずに、どんなSQLが発行されるか事前に確認できます。
本番環境のデータベース設定
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'mydb'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', '5432'),
'CONN_MAX_AGE': 600, # コネクションプール(秒)
}
}
CONN_MAX_AGEを設定すると、データベース接続を再利用できます。リクエストごとに接続・切断するオーバーヘッドを削減し、パフォーマンスが向上します。
STEP 4Gunicorn / uWSGI の設定
Djangoの開発サーバー(runserver)は本番環境で使用してはいけません。本番環境ではGunicornやuWSGIなどのWSGIサーバーを使います。
runserverは単一プロセス・単一スレッドで、パフォーマンスやセキュリティが本番環境に適していません。公式ドキュメントでも本番使用は非推奨と明記されています。
Gunicorn のインストールと基本設定
pip install gunicorn
# 基本的な起動コマンド
gunicorn myproject.wsgi:application --bind 0.0.0.0:8000
# ワーカー数を指定して起動
gunicorn myproject.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 3 \
--timeout 120 \
--access-logfile - \
--error-logfile -
ワーカー数の目安
| CPUコア数 | 推奨ワーカー数 | 計算式 |
|---|---|---|
| 1 | 3 | (CPUコア数 x 2) + 1 |
| 2 | 5 | |
| 4 | 9 | |
| 8 | 17 |
Gunicorn 設定ファイル
コマンドライン引数が増えてきたら、設定ファイルにまとめるのがおすすめです。
import multiprocessing
bind = '0.0.0.0:8000'
workers = multiprocessing.cpu_count() * 2 + 1
timeout = 120
accesslog = '-'
errorlog = '-'
loglevel = 'info'
# グレースフルリスタート対応
graceful_timeout = 30
max_requests = 1000 # メモリリーク対策
max_requests_jitter = 50 # 全ワーカー同時再起動を防止
# 設定ファイルを指定して起動
gunicorn myproject.wsgi:application -c gunicorn.conf.py
uWSGI を使う場合
pip install uwsgi
uwsgi --http :8000 \
--module myproject.wsgi:application \
--master \
--processes 4 \
--threads 2
| 項目 | Gunicorn | uWSGI |
|---|---|---|
| 設定の簡単さ | シンプル | 多機能だが複雑 |
| パフォーマンス | 十分高速 | やや高速 |
| ドキュメント | 読みやすい | 量が多い |
| おすすめ | 初心者〜中級者 | 大規模・高負荷環境 |
STEP 5nginx との連携
Gunicorn単体でもリクエストを処理できますが、本番環境では前段にnginxを配置するのが一般的です。nginxは静的ファイルの配信、SSL終端、リバースプロキシとして機能します。
nginx + Gunicorn の構成図
静的ファイル(/static/, /media/)はnginxが直接配信し、Djangoの負荷を軽減します。
nginx の設定
upstream django {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 静的ファイル
location /static/ {
alias /app/staticfiles/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# メディアファイル
location /media/ {
alias /app/media/;
expires 7d;
}
# Djangoへのプロキシ
location / {
proxy_pass http://django;
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;
proxy_redirect off;
}
# アップロードサイズ制限
client_max_body_size 10M;
}
nginx 設定のポイント
| 設定 | 説明 |
|---|---|
upstream django |
Gunicornのアドレスを定義。複数サーバーでロードバランシングも可能 |
location /static/ |
静的ファイルをnginxから直接配信(Djangoを経由しない) |
X-Forwarded-Proto |
DjangoにHTTPS判定させるために必要(SECURE_PROXY_SSL_HEADERと連携) |
client_max_body_size |
リクエストボディの最大サイズ。大きなファイルアップロードがある場合は調整 |
# 設定を有効化
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/
# 設定の構文チェック
sudo nginx -t
# nginx を再起動
sudo systemctl reload nginx
nginx -tで構文チェックを実行してください。構文エラーのままreloadすると、nginxが停止してサービスダウンする可能性があります。
STEP 6デプロイチェックリスト(manage.py check --deploy)
Djangoには、本番環境向けの設定を自動チェックするコマンドが用意されています。デプロイ前に必ず実行しましょう。
チェックコマンドの実行
python manage.py check --deploy
問題がある場合は、以下のような警告が表示されます。
主な警告IDと対処法
| 警告ID | 内容 | 対処 |
|---|---|---|
security.W004 |
SECURE_HSTS_SECONDS未設定 | SECURE_HSTS_SECONDS = 31536000 |
security.W008 |
SECURE_SSL_REDIRECT未設定 | SECURE_SSL_REDIRECT = True |
security.W012 |
SESSION_COOKIE_SECURE未設定 | SESSION_COOKIE_SECURE = True |
security.W016 |
CSRF_COOKIE_SECURE未設定 | CSRF_COOKIE_SECURE = True |
security.W018 |
DEBUG=True | DEBUG = False |
security.W019 |
X_FRAME_OPTIONS未設定 | X_FRAME_OPTIONS = 'DENY' |
デプロイチェックリスト
以下のチェックリストを使って、デプロイ前にすべての項目を確認してください。
settings.py の設定
-
DEBUG = False -
SECRET_KEYを環境変数で管理 -
ALLOWED_HOSTSにドメイン名を設定 -
SECURE_SSL_REDIRECT = True -
SESSION_COOKIE_SECURE = True -
CSRF_COOKIE_SECURE = True -
SECURE_HSTS_SECONDSを設定 -
DATABASESを本番DBに設定
デプロイ手順
- データベースのバックアップ取得
-
python manage.py migrate実行 -
python manage.py collectstatic --noinput実行 -
python manage.py check --deployで警告なし - Gunicorn / uWSGI の起動確認
- nginx の設定テスト(
nginx -t) - SSL証明書の有効期限確認
デプロイ後の確認
- HTTPSでアクセスできる
- HTTPがHTTPSにリダイレクトされる
- 静的ファイル(CSS/JS/画像)が正しく表示される
- 管理画面(/admin/)にログインできる
- エラーページ(404/500)が正しく表示される
- ログが正しく出力されている
デプロイスクリプトの例
#!/bin/bash
set -e # エラーが発生したら即座に停止
echo "=== デプロイ開始 ==="
# 1. 最新コードを取得
git pull origin main
# 2. 依存パッケージをインストール
pip install -r requirements.txt
# 3. マイグレーション
python manage.py migrate
# 4. 静的ファイル収集
python manage.py collectstatic --noinput
# 5. デプロイチェック
python manage.py check --deploy
# 6. Gunicorn 再起動
sudo systemctl restart gunicorn
# 7. nginx リロード
sudo systemctl reload nginx
echo "=== デプロイ完了 ==="