Deployment hardening: HTTPS/CSRF settings, loopback-only app port, entrypoint passthrough

- settings: trust nginx X-Forwarded-Proto, mark session and CSRF cookies secure,
  and set the CSRF trusted origins for the ixgltd.com hosts
- docker-compose: bind the app port to 127.0.0.1 only; nginx fronts it, so there
  is no reason for 0.0.0.0
- entrypoint: when the container is given a command, run that instead of always
  starting gunicorn (needed for manage.py shell and the test suite)
- gitignore: keep Celery runtime state and stray local backups out of the tree

No functional change to the application itself.
This commit is contained in:
ixgadmin 2026-09-16 16:39:07 +00:00
parent 6508cc25ef
commit 8f1649aaa1
4 changed files with 28 additions and 1 deletions

6
.gitignore vendored
View file

@ -10,3 +10,9 @@ media/
dist/ dist/
build/ build/
.DS_Store .DS_Store
# Runtime state and stray local backups — never part of the source tree
celerybeat-schedule
*.bak*
*.orig
*.rej

View file

@ -55,7 +55,7 @@ services:
DB_HOST: ixg-postgres DB_HOST: ixg-postgres
DB_PORT: 5432 DB_PORT: 5432
ports: ports:
- "0.0.0.0:8000:8000" - "127.0.0.1:8000:8000"
celery_worker: celery_worker:
build: . build: .

View file

@ -17,6 +17,22 @@ SECRET_KEY = env("DJANGO_SECRET_KEY", default="insecure-dev-key-change-in-produc
DEBUG = env.bool("DJANGO_DEBUG", default=False) DEBUG = env.bool("DJANGO_DEBUG", default=False)
ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["194.164.95.50", "localhost", "127.0.0.1"]) ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["194.164.95.50", "localhost", "127.0.0.1"])
# Trust nginx TLS termination headers
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
USE_X_FORWARDED_HOST = True
SESSION_COOKIE_SECURE = env.bool("SESSION_COOKIE_SECURE", default=True)
CSRF_COOKIE_SECURE = env.bool("CSRF_COOKIE_SECURE", default=True)
CSRF_TRUSTED_ORIGINS = env.list(
"DJANGO_CSRF_TRUSTED_ORIGINS",
default=[
"https://ixgltd.com",
"https://www.ixgltd.com",
"https://app.ixgltd.com",
"https://portal.ixgltd.com",
"https://auth.ixgltd.com",
],
)
INSTALLED_APPS = [ INSTALLED_APPS = [
"grappelli", "grappelli",
"django.contrib.admin", "django.contrib.admin",

View file

@ -13,6 +13,11 @@ python manage.py migrate --noinput || true
echo "Collecting static files..." echo "Collecting static files..."
python manage.py collectstatic --noinput python manage.py collectstatic --noinput
if [ "$#" -gt 0 ]; then
echo "Executing command: $*"
exec "$@"
fi
echo "Starting Gunicorn..." echo "Starting Gunicorn..."
exec gunicorn --bind 0.0.0.0:8000 \ exec gunicorn --bind 0.0.0.0:8000 \
--workers 2 \ --workers 2 \