Djangoデプロイ時の注意点と解決策まとめ【本番環境で失敗しないための完全ガイド】

テックジム東京本校では、情報科目の受験対策指導やAI駆動開発コースもご用意しております。
目次
- 1 1. デプロイ前の基本確認事項
- 2 2. DEBUG設定とSECRET_KEYの管理
- 3 3. 静的ファイル(Static Files)の配信問題
- 4 4. データベース接続エラーと移行(migrate)の注意点
- 5 5. ALLOWED_HOSTSの設定ミス
- 6 6. WSGIサーバー(Gunicorn / uWSGI)の設定
- 7 7. Nginxとのリバースプロキシ設定
- 8 8. メディアファイルのアップロード・配信問題
- 9 9. 環境変数・.envファイルの管理
- 10 10. セキュリティ設定チェックリスト
- 11 11. ログ設定とエラー監視
- 12 12. よくあるエラーと解決策 早見表
- 13 まとめ:Djangoデプロイ チェックリスト
- 14 参考リンク
- 15 ■ゼロから始めるClaudeCode講座のご案内
- 16 ■らくらくPython塾 – 読むだけでマスター
- 17 共通テスト「情報I」対策解説講座
- 18 実践で学ぶPython速習講座
- 19 ■テックジム東京本校
この記事でわかること
- Djangoを本番環境へデプロイするときに必ずぶつかる落とし穴
- エラーの原因と、すぐに使える具体的な解決策
- セキュリティ・パフォーマンス・運用の観点での必須チェックリスト
1. デプロイ前の基本確認事項
本番環境へデプロイする前に、以下のコマンドで設定の問題を自動チェックできます。
python manage.py check --deploy
このコマンドはDjangoが用意しているシステムチェックフレームワークを使い、セキュリティ上の問題や設定の不備を一覧表示してくれます。警告(WARNINGS)をゼロにすることを目標に設定を見直しましょう。
よくある出力例と対応
| チェック項目 | 対処方法 |
|---|---|
WARNINGS: security.W004 |
SECURE_HSTS_SECONDS を設定する |
WARNINGS: security.W008 |
SECURE_SSL_REDIRECT = True にする |
WARNINGS: security.W012 |
SESSION_COOKIE_SECURE = True にする |
ERRORS: ?: (urls.E007) |
URLパターンの重複を修正する |
2. DEBUG設定とSECRET_KEYの管理
問題:本番環境でDEBUG=Trueのままにしてしまう
DEBUG=True のままデプロイすると、エラーページにソースコード・環境変数・設定情報がすべて表示されます。これは重大なセキュリティリスクです。
# ❌ 危険:settings.py に直書き
DEBUG = True
SECRET_KEY = 'django-insecure-xxxxxx'
解決策:環境変数で管理する
# ✅ 正しい方法:settings.py
import os
from decouple import config # python-decouple を使う場合
DEBUG = config('DEBUG', default=False, cast=bool)
SECRET_KEY = config('SECRET_KEY')
# .env ファイル(Gitに含めない!)
DEBUG=False
SECRET_KEY=your-very-long-random-secret-key-here
ポイント:
SECRET_KEYは最低50文字以上のランダム文字列を使用してください。 生成コマンド:python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
3. 静的ファイル(Static Files)の配信問題
問題:CSSや画像が本番環境で表示されない
Djangoの開発サーバー(runserver)は静的ファイルを自動配信しますが、本番環境では自分で配信設定が必要です。
解決策:collectstaticを実行する
# settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # collectstatic の出力先
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'), # 開発時の静的ファイル置き場
]
# デプロイ時に必ず実行
python manage.py collectstatic --noinput
Whitenoise を使って Django 単体で配信する方法
小〜中規模のアプリならWhitenoiseが最もシンプルです。
pip install whitenoise
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # SecurityMiddlewareの直後に追加
...
]
# 圧縮・キャッシュを有効化(本番推奨)
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
4. データベース接続エラーと移行(migrate)の注意点
問題1:本番DBへの接続エラー
django.db.utils.OperationalError: could not connect to server
# settings.py(PostgreSQL の例)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', '5432'),
}
}
問題2:migrateを忘れてテーブルが存在しない
django.db.utils.ProgrammingError: relation "app_model" does not exist
解決策: デプロイスクリプトに migrate を組み込む
#!/bin/bash
# deploy.sh
python manage.py migrate --noinput
python manage.py collectstatic --noinput
gunicorn myproject.wsgi:application
問題3:本番DBに対してmigration競合が発生する
複数のサーバーが同時に migrate を実行すると競合します。
解決策: マイグレーションはデプロイ前に1回だけ実行する仕組みにする(例:CI/CDパイプラインで制御)
5. ALLOWED_HOSTSの設定ミス
問題:400 Bad Request / DisallowedHost エラー
Invalid HTTP_HOST header: 'yourdomain.com'. You may need to add 'yourdomain.com' to ALLOWED_HOSTS.
解決策
# settings.py
ALLOWED_HOSTS = [
'yourdomain.com',
'www.yourdomain.com',
'203.0.113.10', # サーバーのIPアドレス(必要な場合)
]
環境変数で管理する場合:
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
# .env
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
注意:
ALLOWED_HOSTS = ['*']はセキュリティリスクになるため、本番環境では絶対に使わないでください。
6. WSGIサーバー(Gunicorn / uWSGI)の設定
Djangoの開発サーバーを本番で使ってはいけない理由
python manage.py runserver はシングルスレッドかつデバッグ用途のサーバーです。本番環境では Gunicorn または uWSGI を使います。
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 4 \ # CPU数 × 2 + 1 が目安
--timeout 120 \
--access-logfile /var/log/gunicorn/access.log \
--error-logfile /var/log/gunicorn/error.log
gunicorn.conf.py で管理する(推奨)
# gunicorn.conf.py
bind = "0.0.0.0:8000"
workers = 4
worker_class = "gthread"
threads = 2
timeout = 120
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
loglevel = "info"
gunicorn -c gunicorn.conf.py myproject.wsgi:application
systemdで自動起動・自動再起動させる
# /etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn Django Application
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myproject
EnvironmentFile=/var/www/myproject/.env
ExecStart=/var/www/myproject/venv/bin/gunicorn \
-c gunicorn.conf.py \
myproject.wsgi:application
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl enable gunicorn
sudo systemctl start gunicorn
7. Nginxとのリバースプロキシ設定
基本的なNginx設定
# /etc/nginx/sites-available/myproject
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# 静的ファイルはNginxが直接配信(高速)
location /static/ {
alias /var/www/myproject/staticfiles/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# メディアファイル
location /media/ {
alias /var/www/myproject/media/;
}
# Djangoアプリへのプロキシ
location / {
proxy_pass http://127.0.0.1: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;
proxy_connect_timeout 60s;
proxy_read_timeout 120s;
}
}
問題:X-Forwarded-Proto を Django が認識しない
NginxのHTTPSをDjangoが認識できず、リダイレクトループが発生する場合があります。
# settings.py
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
8. メディアファイルのアップロード・配信問題
問題:アップロードしたファイルが表示されない
# settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# urls.py(開発環境のみ)
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
本番環境では
urls.pyのstatic()設定は不要(DEBUG=Falseのとき自動的に無効化されます)。Nginxで配信するのが基本です。
クラウドストレージ(S3等)を使う場合
pip install django-storages boto3
# settings.py
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3StaticStorage'
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = 'ap-northeast-1' # 東京リージョン
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
9. 環境変数・.envファイルの管理
.gitignoreに必ず追加する
# .gitignore
.env
*.env
.env.local
.env.production
python-decoupleを使った管理(推奨)
pip install python-decouple
# settings.py
from decouple import config, Csv
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
DATABASE_URL = config('DATABASE_URL')
本番サーバーへの.envの渡し方
| 方法 | 適用場面 |
|---|---|
サーバーの /etc/environment に記載 |
VPS・専用サーバー |
systemdの EnvironmentFile に指定 |
systemd管理のサービス |
Docker の --env-file オプション |
Dockerコンテナ |
| Heroku Config Vars / AWS Parameter Store | クラウドPaaS |
10. セキュリティ設定チェックリスト
# settings.py(本番環境の推奨設定)
# HTTPS関連
SECURE_SSL_REDIRECT = True # HTTPをHTTPSにリダイレクト
SECURE_HSTS_SECONDS = 31536000 # HSTSを1年間有効化
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Cookie
SESSION_COOKIE_SECURE = True # CookieをHTTPS専用に
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
# クリックジャッキング対策
X_FRAME_OPTIONS = 'DENY'
# コンテンツタイプスニッフィング対策
SECURE_CONTENT_TYPE_NOSNIFF = True
# XSSフィルター
SECURE_BROWSER_XSS_FILTER = True
11. ログ設定とエラー監視
本番環境向けのログ設定
# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': '/var/log/django/error.log',
'formatter': 'verbose',
},
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['file', 'console'],
'level': 'ERROR',
'propagate': True,
},
},
}
メール通知でエラーを受け取る(ADMINS設定)
# settings.py
ADMINS = [('Your Name', 'admin@yourdomain.com')]
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
SERVER_EMAIL = 'server@yourdomain.com'
ADMINSに登録したメールアドレスに、500エラー発生時の詳細なトレースバックが届くようになります。
12. よくあるエラーと解決策 早見表
| エラーメッセージ | 原因 | 解決策 |
|---|---|---|
DisallowedHost |
ALLOWED_HOSTS にドメインがない |
ドメインを ALLOWED_HOSTS に追加 |
CSRF verification failed |
CSRF トークンがない / Cookie設定ミス | フォームに {% csrf_token %} を追加、CSRF_COOKIE_SECURE を確認 |
Static files not found (404) |
collectstatic 未実行 or Nginx設定ミス |
collectstatic 実行後、Nginxのパスを確認 |
OperationalError: no such table |
migrate 未実行 |
python manage.py migrate を実行 |
500 Internal Server Error |
アプリのバグ or 設定ミス | ログファイル(/var/log/django/error.log)を確認 |
[Errno 111] Connection refused |
DB or Redisが起動していない | サービスの起動状態を確認(systemctl status postgresql) |
Invalid HTTP_HOST header |
プロキシの Host ヘッダーが渡されていない |
Nginxで proxy_set_header Host $host; を設定 |
ModuleNotFoundError |
仮想環境にパッケージが入っていない | 本番の venv で pip install -r requirements.txt を実行 |
まとめ:Djangoデプロイ チェックリスト
□ DEBUG=False にしている
□ SECRET_KEY を環境変数で管理している
□ ALLOWED_HOSTS に本番ドメインを設定している
□ python manage.py collectstatic を実行した
□ python manage.py migrate を実行した
□ Gunicorn/uWSGI を使っている(runserver は使っていない)
□ Nginx のリバースプロキシが正しく設定されている
□ HTTPS・セキュリティ設定を有効化している
□ .env ファイルを .gitignore に追加している
□ ログの出力先を設定している
□ python manage.py check --deploy でエラー・警告がない
参考リンク
■ゼロから始めるClaudeCode講座のご案内
テックジム東京本校では「ClaudeCode」の体験講座を開催。
「その日のうちに動かす」 をゴールに、環境構築から実践まで。
毎週土曜日15時。参加は無料です。対面・ハンズオンだから初心者でも安心。
■らくらくPython塾 – 読むだけでマスター
共通テスト「情報I」対策解説講座
実践で学ぶPython速習講座
■テックジム東京本校
格安のプログラミングスクールといえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
対面型でより早くスキル獲得、月額2万円のプログラミングスクールです。
情報科目の受験対策指導やAI駆動開発コースもご用意しております。