refactor(docker): Enhance settings.py and deployment

This commit significantly refactors the Docker setup and application
configuration for improved robustness and flexibility.

Key changes include:

- Centralized Environment Variables:
  - Default values for essential settings (database, email, cache, etc.)
    are now defined in `django_project/settings.py` using `environ.Env`.
    This provides sensible defaults and reduces reliance on `.env` files,
    especially during Docker image builds.
  - `docker-compose.yml` no longer defines environment variables directly
    for `web` and `worker` services, deferring to `.env` and settings defaults.

- Dockerfile & Entrypoint Improvements:
  - `DJANGO_SETTINGS_MODULE` is now exclusively set as an ENV in `Dockerfile`, instead of setting it in `entrypoint.sh`
  - `entrypoint.sh` now conditionally appends `--static-path-mount`
    only to the `granian` command, leveraging the upgraded Granian's
    (v2.3.0+) ability to serve static files directly. The `STATIC_ROOT` is
    dynamically fetched from Django settings.

- Dependency Updates:
  - Upgraded `granian` from 2.2.5 to 2.3.1.
  - Upgraded `click` from 8.2.0 to 8.2.1.
  - `uv.lock` reflects these and other minor transitive dependency updates.

- Configuration Adjustments in `settings.py`:
  - Add defaults for all env variables, and set to default local dev settings
  - Introduced a `SCHEME` environment variable (defaulting to 'http')
    used for `CSRF_TRUSTED_ORIGINS`, `META_SITE_PROTOCOL`,
    `ACCOUNT_DEFAULT_HTTP_PROTOCOL`, etc.
  - `TIME_ZONE` and various email settings (host, port, user, password, TLS)
    are now configurable via environment variables with defaults.
  - `CELERY_TIMEZONE` now defaults to the `TIME_ZONE` setting.
  - Removed the unused `SCW_SECRET_KEY` variable (previously used for
    EMAIL auth).
This commit is contained in:
badblocks 2025-05-23 18:46:20 -07:00
parent d4948e7cd3
commit 02f23dba28
No known key found for this signature in database
6 changed files with 90 additions and 93 deletions

View file

@ -5,8 +5,27 @@ import os
import logging
import sys
# set default values to dev values for environment variables
env = environ.Env(
DEBUG=(bool, False)
DEBUG=(bool, False), # MUST STAY FALSE FOR DEFAULT FOR SECURITY REASONS (e.g. if app can't access .env, prevent showing debug output)
DISABLE_SIGNUPS=(bool, False),
DISABLE_CACHE=(bool, False),
DJANGO_DATABASE_URL=(str, 'postgresql://postgres@db:5432/postgres?sslmode=disable'),
DJANGO_EMAIL_HOST=(str, ''),
DJANGO_EMAIL_PORT=(int, 587),
DJANGO_EMAIL_USER=(str, ''),
DJANGO_EMAIL_PASSWORD=(str, ''),
DJANGO_EMAIL_USE_TLS=(bool, True),
DJANGO_DEFAULT_FROM_EMAIL=(str, ''),
SECRET_KEY=(str, '0000000000000000000000000000000000000000000000000000000000000000'),
ALLOWED_HOSTS=(str, 'localhost,127.0.0.1'),
PUBLIC_HOST=(str, 'localhost'),
ACCOUNT_EMAIL_VERIFICATION=(str, 'none'),
DJANGO_SETTINGS_MODULE=(str, 'pkmntrade_club.django_project.settings'),
SCHEME=(str, 'http'),
REDIS_URL=(str, 'redis://redis:6379'),
CACHE_TIMEOUT=(int, 604800),
TIME_ZONE=(str, 'America/Los_Angeles'),
)
LOGGING = {
@ -59,6 +78,13 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# Take environment variables from .env file
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
SCHEME = env('SCHEME')
PUBLIC_HOST = env('PUBLIC_HOST')
REDIS_URL = env('REDIS_URL')
CACHE_TIMEOUT = env('CACHE_TIMEOUT')
DISABLE_SIGNUPS = env('DISABLE_SIGNUPS')
DISABLE_CACHE = env('DISABLE_CACHE')
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/
@ -66,11 +92,6 @@ environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')
# Scaleway Secret Key
SCW_SECRET_KEY = env('SCW_SECRET_KEY')
DISABLE_SIGNUPS = env('DISABLE_SIGNUPS', default=False)
# https://docs.djangoproject.com/en/dev/ref/settings/#debug
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env('DEBUG')
@ -85,9 +106,7 @@ try:
except Exception:
logging.getLogger(__name__).info(f"Error determining server hostname for allowed hosts.")
PUBLIC_HOST = env('PUBLIC_HOST')
CSRF_TRUSTED_ORIGINS = [f"https://{PUBLIC_HOST}"]
CSRF_TRUSTED_ORIGINS = [f"{SCHEME}://{PUBLIC_HOST}"]
FIRST_PARTY_APPS = [
'pkmntrade_club.accounts',
@ -140,9 +159,9 @@ if DEBUG:
TAILWIND_APP_NAME = 'theme'
META_SITE_NAME = 'PKMN Trade Club'
META_SITE_PROTOCOL = 'https'
META_SITE_PROTOCOL = SCHEME
META_USE_SITES = True
META_IMAGE_URL = f'https://{PUBLIC_HOST}/'
META_IMAGE_URL = f'{SCHEME}://{PUBLIC_HOST}/'
# https://docs.djangoproject.com/en/dev/ref/settings/#middleware
MIDDLEWARE = [
@ -228,7 +247,7 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = "en-us"
# https://docs.djangoproject.com/en/dev/ref/settings/#time-zone
TIME_ZONE = "UTC"
TIME_ZONE = env('TIME_ZONE')
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-USE_I18N
USE_I18N = True
@ -281,19 +300,14 @@ CRISPY_TEMPLATE_PACK = "tailwind"
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
# EMAIL_HOST = "smtp.resend.com"
# EMAIL_PORT = 587
# EMAIL_HOST_USER = "resend"
# EMAIL_HOST_PASSWORD = RESEND_API_KEY
# EMAIL_USE_TLS = True
EMAIL_HOST = "smtp.tem.scaleway.com"
EMAIL_PORT = 587
EMAIL_HOST_USER = "dd2cd354-de6d-4fa4-bfe8-31c961cb4e90"
EMAIL_HOST_PASSWORD = SCW_SECRET_KEY
EMAIL_USE_TLS = True
EMAIL_HOST = env('DJANGO_EMAIL_HOST')
EMAIL_PORT = env('DJANGO_EMAIL_PORT')
EMAIL_HOST_USER = env('DJANGO_EMAIL_USER')
EMAIL_HOST_PASSWORD = env('DJANGO_EMAIL_PASSWORD')
EMAIL_USE_TLS = env('DJANGO_EMAIL_USE_TLS')
# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
DEFAULT_FROM_EMAIL = "noreply@pkmntrade.club"
DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL')
# django-debug-toolbar
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html
@ -302,7 +316,7 @@ INTERNAL_IPS = [
"127.0.0.1",
]
# for docker + debug toolbar
# for docker
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
for ip in ips:
INTERNAL_IPS.append(ip)
@ -337,7 +351,7 @@ ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = env('ACCOUNT_EMAIL_VERIFICATION')
ACCOUNT_EMAIL_NOTIFICATIONS = True
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https"
ACCOUNT_DEFAULT_HTTP_PROTOCOL = SCHEME
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True
ACCOUNT_USERNAME_MIN_LENGTH = 2
ACCOUNT_CHANGE_EMAIL = True
@ -353,14 +367,9 @@ SOCIALACCOUNT_EMAIL_AUTHENTICATION = False
SOCIALACCOUNT_EMAIL_AUTHENTICATION_AUTO_CONNECT = False
SOCIALACCOUNT_ONLY = False
CACHE_TIMEOUT = 604800 # 1 week
# auto-detection doesn't work properly sometimes, so we'll just use the DEBUG setting
DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": lambda request: DEBUG}
REDIS_URL = "redis://redis:6379"
DISABLE_CACHE = env('DISABLE_CACHE', default=DEBUG)
if DISABLE_CACHE:
CACHES = {
"default": {
@ -377,6 +386,6 @@ else:
CELERY_BROKER_URL = REDIS_URL
CELERY_RESULT_BACKEND = REDIS_URL
CELERY_TIMEZONE = "America/Los_Angeles"
CELERY_TIMEZONE = TIME_ZONE
CELERY_ENABLE_UTC = True
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"