基本

Djangoデプロイチェックリスト|本番環境に安全に公開する

Django デプロイ 本番環境

Djangoデプロイチェックリスト
本番環境に安全に公開する

Djangoアプリケーションを本番環境にデプロイする手順とチェックリストを解説。Gunicorn、nginx連携、セキュリティ設定まで学べます。

こんな人向けの記事です

  • Djangoアプリを本番環境に公開したい
  • デプロイ時の設定漏れを防ぎたい
  • Gunicorn+nginxの構成を理解したい

STEP 1デプロイ前の準備(DEBUG=False, ALLOWED_HOSTS)

Djangoアプリを本番環境に公開する前に、最低限変更しなければならない設定があります。これらを忘れると、セキュリティ上の深刻な問題を引き起こします。

DEBUG = False に設定する

DEBUG=Trueのまま本番運用すると、エラー発生時にスタックトレース、環境変数、URLパターンなどの内部情報がブラウザに表示されてしまいます。必ずFalseに設定してください。

settings.py
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になります。

settings.py
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')

# 例: ALLOWED_HOSTS=example.com,www.example.com
ポイント
ALLOWED_HOSTS = ['*']はすべてのホスト名を受け入れてしまうため、本番環境では使用しないでください。Hostヘッダー攻撃の原因になります。

SECRET_KEY を環境変数で管理する

SECRET_KEYはセッション、CSRFトークン、パスワードリセットなどの暗号処理に使われます。ソースコードに直書きせず、環境変数で管理してください。

settings.py
SECRET_KEY = os.environ.get('SECRET_KEY')
if not SECRET_KEY:
    raise ValueError('SECRET_KEY環境変数が設定されていません')
ローカル(自分のPC)
# 安全なキーの生成方法
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"

本番用settings.pyの全体像

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 を設定する

settings.py
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
Found 128 static files. 128 static files copied to '/app/staticfiles'.
--noinput オプション
--noinputを付けると確認プロンプトなしで実行されます。CI/CDパイプラインやDockerビルド時に便利です。

WhiteNoise で簡易配信する方法

nginx無しで静的ファイルを配信したい場合は、WhiteNoiseミドルウェアが便利です。

ターミナル
pip install whitenoise
settings.py
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 コマンド
sqlmigrateはマイグレーションが実行するSQLを表示するコマンドです。実際にDBを変更せずに、どんなSQLが発行されるか事前に確認できます。

本番環境のデータベース設定

settings.py
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
CONN_MAX_AGEを設定すると、データベース接続を再利用できます。リクエストごとに接続・切断するオーバーヘッドを削減し、パフォーマンスが向上します。

STEP 4Gunicorn / uWSGI の設定

Djangoの開発サーバー(runserver)は本番環境で使用してはいけません。本番環境ではGunicornuWSGIなどのWSGIサーバーを使います。

runserver を本番で使わない理由
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 設定ファイル

コマンドライン引数が増えてきたら、設定ファイルにまとめるのがおすすめです。

gunicorn.conf.py
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 の構成図

リクエストの流れ
クライアント → nginx(:443 / :80)→ Gunicorn(:8000)→ Django
静的ファイル(/static/, /media/)はnginxが直接配信し、Djangoの負荷を軽減します。

nginx の設定

/etc/nginx/sites-available/myproject
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 を必ず実行する
設定変更後は必ずnginx -tで構文チェックを実行してください。構文エラーのままreloadすると、nginxが停止してサービスダウンする可能性があります。

STEP 6デプロイチェックリスト(manage.py check --deploy)

Djangoには、本番環境向けの設定を自動チェックするコマンドが用意されています。デプロイ前に必ず実行しましょう。

チェックコマンドの実行

サーバー上
python manage.py check --deploy
System check identified no issues (0 silenced).

問題がある場合は、以下のような警告が表示されます。

?: (security.W004) You have not set a value for the SECURE_HSTS_SECONDS setting. ?: (security.W008) Your SECURE_SSL_REDIRECT setting is not set to True. ?: (security.W012) SESSION_COOKIE_SECURE is not set to True.

主な警告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)が正しく表示される
  • ログが正しく出力されている
自動化のすすめ
上記の手順はシェルスクリプトやCI/CDパイプラインで自動化するのがベストプラクティスです。手動デプロイはミスの原因になります。

デプロイスクリプトの例

deploy.sh
#!/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 "=== デプロイ完了 ==="