◀ 2.

CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.

▶
この記事の要点
  • Django の runserver を DEBUG = False で起動したのに ALLOWED_HOSTS が空のときに出るエラー
  • 対処: settings.py の ALLOWED_HOSTS に、アクセスに使うホスト名(ドメイン・IP)を書く
  • ローカル確認なら ['127.0.0.1', 'localhost']、本番なら ['example.com', 'www.example.com'] など
  • ['*'] はすべてのホストを許可するため、本番では推奨されない
  • 環境変数から DEBUG を読むとき、文字列 "False" は真として扱われる落とし穴に注意

エラー内容

CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.

python manage.py runserver を実行した直後に表示され、開発サーバーが起動しません。

原因

settings.py で DEBUG が False になっているにもかかわらず、ALLOWED_HOSTS が設定されていない(空のリスト)ときに発生するエラーです。

ALLOWED_HOSTS は「この Django サイトがどのホスト名で呼ばれたときに応答してよいか」を決める設定です。リクエストの Host ヘッダーを偽装する攻撃(HTTP Host ヘッダー攻撃)を防ぐための仕組みで、パスワードリセットメール内の URL が攻撃者のドメインにすり替わる、といった被害を防ぎます。

  • DEBUG = True のとき: ALLOWED_HOSTS が空でも、localhost や 127.0.0.1 などローカルからのアクセスは自動で許可されます。そのため開発中は気付きにくい設定です
  • DEBUG = False のとき: 自動の許可は無くなり、明示的に書いたホストしか受け付けません。空のままだと runserver はこのエラーで起動を拒否します

つまり「本番を想定して DEBUG を False にした」「本番用の設定ファイルに切り替えた」タイミングで初めて出会うエラーです。

対処法

settings.py に、実際にアクセスするときのホスト名を書きます。

DEBUG = False

# ALLOWED_HOSTS = ['*']   # すべて許可(本番では非推奨)
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']

本番環境では、公開するドメインを書きます。

ALLOWED_HOSTS = ['example.com', 'www.example.com']

# 先頭にドットを付けると、そのドメインとすべてのサブドメインを許可する
# ALLOWED_HOSTS = ['.example.com']

書き方のルール

書き方許可されるもの
'example.com'example.com だけ(www.example.com は不可)
'.example.com'example.com と、www.example.com などすべてのサブドメイン
'192.0.2.10'IP アドレスで直接アクセスした場合
'*'すべてのホスト(Host ヘッダーの検証を事実上無効にする)

ポート番号やスキーム(http://)は書きません。'example.com:8000' や 'https://example.com' のように書くと一致しません。

環境ごとに切り替える書き方

開発と本番で値が違うため、環境変数から読み込む書き方がよく使われます。

import os

DEBUG = os.environ.get('DJANGO_DEBUG', 'False') == 'True'

ALLOWED_HOSTS = [
    h.strip()
    for h in os.environ.get('DJANGO_ALLOWED_HOSTS', '').split(',')
    if h.strip()
]
export DJANGO_DEBUG=False
export DJANGO_ALLOWED_HOSTS=example.com,www.example.com
python manage.py runserver

注意: DEBUG = os.environ.get('DJANGO_DEBUG', False) のように書くと、環境変数に文字列の "False" を設定しても空でない文字列なので真として扱われ、本番で DEBUG が有効になってしまいます。上の例のように文字列と比較して真偽値に変換してください。

runserver 以外で起きる関連エラー

このエラーは runserver コマンドが出すものです。gunicorn や uWSGI など本番用のサーバーで動かしている場合は起動時にはエラーにならず、許可されていないホストへのアクセスに対して 400 Bad Request が返り、ログに「Invalid HTTP_HOST header: 'xxx'. You may need to add 'xxx' to ALLOWED_HOSTS.」と記録されます。ログに出たホスト名が正当なものであれば ALLOWED_HOSTS に追加します。

  • ロードバランサーのヘルスチェックが IP アドレスでアクセスしてくる場合、その IP も許可が必要になることがあります
  • リバースプロキシ(nginx など)の背後では、プロキシが Host ヘッダーを正しく転送しているか(proxy_set_header Host $host;)も確認します
  • Django 4.0 以降、HTTPS のフォーム送信で CSRF エラーが出る場合は CSRF_TRUSTED_ORIGINS にスキーム付きの URL(https://example.com)を設定します

DEBUG = False にしたときのその他の注意点

  • 静的ファイルが表示されなくなる: DEBUG = False の runserver は CSS や画像などの静的ファイルを配信しません。本番では collectstatic で集めて nginx などから配信するか、WhiteNoise などを使います。ローカルで確認するだけなら runserver --insecure で配信できます
  • エラー画面が簡素になる: 詳細なエラーページは表示されなくなるため、ログ(LOGGING 設定)や ADMINS へのメール通知で原因を確認します
  • 404 / 500 のテンプレート: templates に 404.html / 500.html を置くと独自のエラーページを表示できます

確認方法

  1. python manage.py runserver がエラーなく起動することを確認する
  2. ALLOWED_HOSTS に書いたホスト名でブラウザからアクセスし、ページが表示されることを確認する
  3. python manage.py check --deploy を実行し、本番向けのセキュリティ設定に警告が出ていないかを確認する

関連

子ページ

子ページはありません

同階層のページ
  1. Invalid HTTP_HOST header: '...'. You may need to add '...' to ALLOWED_HOSTS
  2. CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.
  3. django.utils.datastructures.MultiValueDictKeyError
  4. Forbidden (403) CSRF verification failed. Request aborted.
  5. ModuleNotFoundError: No module named 'MySQLdb'
  6. WARNINGS: ?: (mysql.W002) MySQL Strict Mode is not set for database connection
  7. Unknown column 'table_name.id' in 'field list'
  8. RuntimeError: Model class ~ doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
  9. get() returned more than one MynumberRegist -- it returned 2!
  10. django.db.utils.OperationalError: (2006, "Can't connect to MySQL server")
  11. 'include' is not defined