Best Practices for Securing Django in Production

Search for a command to run...

No comments yet. Be the first to comment.
There's a question that most people feel but almost nobody says out loud. Not because it's complicated. Because saying it threatens everything built on top of not saying it. The question is simple. Wh

Public discourse around personal finance in India increasingly relies on lifestyle narratives, absolute numbers, and loosely imported benchmarks. Concepts such as middle class, financial security, high income, or wealthy are often used without refere...

By Ahmad W Khan (interactive at https://ahmadwkhan.com/india-work-landscape) Summary (TL;DR): India’s labour market is vast, diversified, and uneven. Government roles remain tenure‑rich but hard to enter; healthcare and licensed professional practice...

Audience: Intermediate PHP devs (comfortable with OOP, Composer, basic MVC) who are new/rusty with SymfonyOS Assumptions: macOS/Linux primary; Windows notes included (PowerShell + WSL2)Target PHP & Symfony: PHP 8.2+ and Symfony 7.3.x (current stable ...

Money, unlike geography, is invisible.We know where a country starts and ends on a map. But wealth and income? They’re like air currents, everywhere, yet hard to see. Percentiles help make them visible: where do you sit compared to your neighbors, yo...

Deploying Django in production requires careful security configurations, especially when using cloud platforms like AWS, DigitalOcean, GCP, or Azure. While Django provides security features out of the box, a misconfigured production environment can expose your application to attacks.
This guide will expand on common security mistakes and how to configure Django securely in production with best practices for AWS, DigitalOcean, GCP, and other cloud platforms.
Leaving DEBUG=True in production is a major security risk. It exposes environment variables, database credentials, and internal stack traces.
Fix:
import os
DEBUG = os.getenv("DJANGO_DEBUG", "False") == "True"
ALLOWED_HOSTS = ["yourdomain.com"]
Use environment variables to manage settings securely instead of hardcoding them.
Only allow requests from your domain:
ALLOWED_HOSTS = ["yourdomain.com", "api.yourdomain.com"]
For cloud-based environments (AWS/GCP), set ALLOWED_HOSTS dynamically:
ALLOWED_HOSTS = os.getenv("DJANGO_ALLOWED_HOSTS", "").split(",")
Never hardcode database credentials in settings.py. Instead, store them in AWS SSM Parameter Store, GCP Secret Manager, DigitalOcean App Secrets, or .env files.
Example for AWS RDS / PostgreSQL:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv("DB_NAME"),
'USER': os.getenv("DB_USER"),
'PASSWORD': os.getenv("DB_PASSWORD"),
'HOST': os.getenv("DB_HOST"), # RDS instance or Cloud SQL
'PORT': os.getenv("DB_PORT", "5432"),
'OPTIONS': {
'sslmode': 'require', # Enforce SSL
},
}
}
Instead of storing passwords, use IAM authentication with AWS RDS:
psql "host=your-rds-instance.amazonaws.com dbname=yourdb sslmode=verify-full sslrootcert=rds-ca.pem"
For PostgreSQL on AWS RDS, DigitalOcean DBaaS, or GCP Cloud SQL, enforce SSL to encrypt data in transit.
'OPTIONS': {
'sslmode': 'require',
}
Verify with:
psql "sslmode=require"
Serving static and media files via S3, DigitalOcean Spaces, or Google Cloud Storage (GCS) reduces server load and increases security.
Example for AWS S3:
INSTALLED_APPS += ["storages"]
AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME")
AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com"
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
For DigitalOcean Spaces:
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
AWS_S3_ENDPOINT_URL = "https://nyc3.digitaloceanspaces.com"
For Google Cloud Storage (GCP):
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
GS_BUCKET_NAME = os.getenv("GS_BUCKET_NAME")
Set private permissions for user-uploaded files.
Use pre-signed URLs for downloads.
AWS_S3_OBJECT_PARAMETERS = {
"CacheControl": "max-age=86400",
"ACL": "private"
}
Enable Argon2 for better security:
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.Argon2PasswordHasher',
]
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
Use django-otp for MFA in Django Admin:
pip install django-otp
Add to INSTALLED_APPS:
INSTALLED_APPS += ["django_otp", "django_otp.plugins.otp_totp"]
Always use ORM or parameterized queries:
cursor.execute("SELECT * FROM users WHERE username = %s", [username])
Use Django’s auto-escaping in templates.
Enable content security policy (CSP) middleware:
pip install django-csp
Add CSP Headers:
MIDDLEWARE += ["csp.middleware.CSPMiddleware"]
CSP_DEFAULT_SRC = ["'self'"]
CSP_SCRIPT_SRC = ["'self'", "'unsafe-inline'"]
gunicorn --workers 3 myproject.wsgi
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"file": {
"level": "ERROR",
"class": "logging.FileHandler",
"filename": "/var/log/django_errors.log",
},
},
"loggers": {
"django": {
"handlers": ["file"],
"level": "ERROR",
"propagate": True,
},
},
}
For AWS ECS or EC2, install CloudWatch Agent:
sudo yum install amazon-cloudwatch-agent
Configure awslogs:
[general]
state_file = /var/awslogs/state/agent-state
[/var/log/django]
file = /var/log/django_errors.log
log_group_name = django_logs
Start logging service:
sudo systemctl start awslogs
For AWS RDS, create security groups:
aws ec2 authorize-security-group-ingress --group-id sg-12345 --protocol tcp --port 5432 --source-ip your-server-ip/32
For DigitalOcean, enable Cloud Firewalls.
For GCP, restrict database access using VPC firewall rules.
aws waf create-web-acl --name MyWebACL
For Cloudflare, enable DDoS protection under Firewall Rules.
Securing Django in production requires configuring security settings, using cloud-native security tools, and continuously monitoring vulnerabilities. Whether deploying on AWS, DigitalOcean, GCP, or other platforms, follow these best practices to keep your application secure.
Feel free to reach me at AhmadWKhan.com to discuss your application’s security issues.