Настройки для продакшена и секреты

Один и тот же settings.py не годится и для разработки, и для прода. Разделение настроек и вынос секретов — первый шаг к боевому развёртыванию.
Суть: секреты (SECRET_KEY, пароли) держат в переменных окружения, а не в коде. Для прода переключают DEBUG=False, заполняют ALLOWED_HOSTS и настраивают реальную базу. Часто разделяют настройки на base/dev/prod.

Почему настройки нужно разделять

В разработке удобно: DEBUG=True, SQLite, подробные ошибки. В продакшене всё наоборот: DEBUG=False, PostgreSQL, скрытые трассировки, HTTPS. Держать оба режима в одном файле с условиями — путаница и риск выкатить отладочный режим на боевой сервер. Поэтому настройки разделяют или параметризуют через окружение.

Секреты — в окружение, не в код

Главное правило безопасности: никаких секретов в git. SECRET_KEY, пароли базы, ключи API читают из переменных окружения. Локально их хранят в файле .env (который добавлен в .gitignore):

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
DEBUG = os.environ.get("DJANGO_DEBUG", "False") == "True"
ALLOWED_HOSTS = os.environ.get("DJANGO_HOSTS", "").split(",")

Боевая база данных

SQLite хорош для разработки, но в продакшене берут PostgreSQL — он выдерживает параллельные записи и большие объёмы. Настройка тоже через окружение:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": os.environ["DB_NAME"],
        "USER": os.environ["DB_USER"],
        "PASSWORD": os.environ["DB_PASSWORD"],
        "HOST": os.environ.get("DB_HOST", "localhost"),
        "PORT": os.environ.get("DB_PORT", "5432"),
    }
}

Как это работает под капотом

Чтение конфигурации из окружения с дефолтами — языко-независимая логика «возьми переменную или подставь значение по умолчанию, приведя к нужному типу». Вот её модель:

# Попробуй сам ▶ — чтение настроек из окружения
fake_env = {
    "DJANGO_DEBUG": "False",
    "DJANGO_HOSTS": "example.com,www.example.com",
    "DB_PORT": "5432",
}

def env(key, default=None, cast=str):
    raw = fake_env.get(key, default)
    if raw is None:
        raise KeyError(f"Не задана обязательная переменная {key}")
    if cast is bool:
        return str(raw).lower() in ("true", "1", "yes")
    if cast is list:
        return [x.strip() for x in str(raw).split(",") if x.strip()]
    return cast(raw)

DEBUG = env("DJANGO_DEBUG", "False", bool)
HOSTS = env("DJANGO_HOSTS", "", list)
PORT  = env("DB_PORT", "5432", int)

print("DEBUG:", DEBUG, type(DEBUG).__name__)
print("HOSTS:", HOSTS)
print("PORT :", PORT, type(PORT).__name__)

Библиотеки вроде django-environ делают то же самое, но с разбором .env-файлов и приведением типов из коробки.

Логирование вместо print

В разработке отладочный вывод делают через print, но в продакшене это бесполезно: вывод теряется, не пишется в файлы и не различает уровни важности. Django использует стандартный модуль logging Python, настраиваемый словарём LOGGING в settings. Вы задаёте обработчики (вывод в файл, в консоль, отправка ошибок на почту), уровни (DEBUG, INFO, WARNING, ERROR) и форматтеры. На проде обычно пишут WARNING и выше в файл или внешний сервис сбора логов, а критические ошибки шлют команде. Грамотно настроенное логирование — это глаза и уши приложения в бою: без него вы узнаёте о проблеме только от рассерженных пользователей. Поэтому логирование настраивают сразу, а не «когда-нибудь потом».

Структура split-settings

Популярный подход — папка settings/ с файлами base.py (общее), dev.py (импортирует base, добавляет отладку) и prod.py (импортирует base, ужесточает безопасность). Какой использовать — выбирает переменная DJANGO_SETTINGS_MODULE.

settings/
├── base.py   ── общие настройки (INSTALLED_APPS, шаблоны)
├── dev.py    ── from .base import *; DEBUG=True; SQLite
└── prod.py   ── from .base import *; DEBUG=False; Postgres; HTTPS

Частые ошибки

  • Коммитить SECRET_KEY и пароли в git. Утечка из истории репозитория — частая причина взломов.
  • Оставить DEBUG=True на проде. Любая ошибка покажет посетителю трассировку с кодом и настройками.
  • Пустой ALLOWED_HOSTS при DEBUG=False. Сайт вернёт ошибку на все запросы.
  • Использовать SQLite в продакшене под нагрузкой. Блокировки при параллельной записи.

Best practices

  • Все секреты — через переменные окружения; .env в .gitignore.
  • Разделяйте настройки на base/dev/prod или параметризуйте через окружение.
  • В продакшене: PostgreSQL, DEBUG=False, заполненный ALLOWED_HOSTS.
  • Сгенерируйте новый SECRET_KEY для прода, не используйте дефолтный из шаблона.

Итоги

Настройки для разработки и прода разные. Секреты живут в окружении, не в коде. Прод требует DEBUG=False, заполненного ALLOWED_HOSTS и боевой базы PostgreSQL. Разделение на base/dev/prod наводит порядок. Теперь развернём приложение на боевом сервере.

Проверьте себя
1. Где хранить SECRET_KEY и пароли базы?
AПрямо в settings.py
BВ переменных окружения, вне git
CВ шаблоне HTML
DВ публичном README
2. Чем грозит DEBUG=True на продакшене?
AСайт работает быстрее
BПри ошибке посетитель увидит трассировку с кодом и настройками
CНичем особенным
DБаза станет недоступна