Introduction
Deploying a Django project into production is one of the most crucial steps in the web development lifecycle. While developing locally, you might be using Django’s built-in development server, SQLite database, and debug mode. However, once you move to production, the environment must be configured for security, scalability, and performance.
This detailed guide will walk you through all the essential steps to prepare your Django project for a real-world production deployment. You will learn how to set up your environment, secure sensitive information, configure databases, manage static files, enable caching, and apply best practices to make your Django application stable and secure in production.
Understanding Development vs. Production Environments
Before diving into configuration, it’s important to understand the difference between development and production environments.
- Development Environment:
Used for building and testing new features. Debugging and live error reporting are enabled to make it easier to identify problems. - Production Environment:
The live environment where your users access your application. Security, performance, and stability are the priorities here.
Key differences:
| Feature | Development | Production |
|---|---|---|
| Debug Mode | Enabled | Disabled |
| Database | Usually SQLite | PostgreSQL or MySQL |
| Error Reporting | Detailed | Hidden from users |
| Security | Relaxed | Strict |
| Logging | Minimal | Centralized and structured |
| Server | runserver | Gunicorn / uWSGI + Nginx |
With this foundation, let’s begin preparing your Django project for production deployment.
Step 1: Setting Up a Virtual Environment
A virtual environment isolates your project’s dependencies, ensuring that package versions and libraries used in your project don’t conflict with others on the system.
Creating a Virtual Environment
To create a new virtual environment, navigate to your project directory and run:
python -m venv venv
This creates a folder named venv containing a clean Python environment.
Activating the Virtual Environment
To activate the environment, use the following command depending on your operating system:
For macOS/Linux:
source venv/bin/activate
For Windows:
venv\Scripts\activate
You should now see (venv) at the start of your terminal prompt, indicating that your virtual environment is active.
Step 2: Installing Project Dependencies
Once your virtual environment is active, install all required packages using the requirements.txt file.
pip install -r requirements.txt
This command ensures all dependencies used during development are installed in the virtual environment. If you don’t have a requirements.txt file yet, create one using:
pip freeze > requirements.txt
This file will list all packages and their versions, which is crucial for consistent deployment.
Step 3: Managing Environment Variables
Hardcoding sensitive information like secret keys, database passwords, and API credentials in settings.py is a major security risk. Instead, you should store them in environment variables.
Two popular Python packages for this are:
python-decoupledjango-environ
Installing python-decouple
You can install it using pip:
pip install python-decouple
Creating a .env File
In your project root directory, create a file named .env and add your sensitive configuration values:
SECRET_KEY=your_production_secret_key_here
DEBUG=False
DATABASE_NAME=production_db
DATABASE_USER=db_user
DATABASE_PASSWORD=db_password
DATABASE_HOST=localhost
DATABASE_PORT=5432
Reading Environment Variables in Django
Update your settings.py to load variables from the .env file:
from decouple import config
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
This ensures that sensitive data is not exposed in your source code.
Step 4: Configuring the Database for Production
Django uses SQLite as the default database, which is fine for local development. However, for production environments, you need a more robust, scalable database like PostgreSQL or MySQL.
Using PostgreSQL
Install PostgreSQL and the required Python adapter:
pip install psycopg2-binary
Then, update your settings.py to use PostgreSQL:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DATABASE_NAME'),
'USER': config('DATABASE_USER'),
'PASSWORD': config('DATABASE_PASSWORD'),
'HOST': config('DATABASE_HOST', default='localhost'),
'PORT': config('DATABASE_PORT', default='5432'),
}
}
This connects your Django application to a PostgreSQL database configured via environment variables.
Step 5: Disabling Debug Mode
In development, you typically set DEBUG = True to view detailed error pages. However, this setting must never be enabled in production because it can expose sensitive system information to users.
In settings.py, use:
DEBUG = config('DEBUG', default=False, cast=bool)
Make sure your .env file includes:
DEBUG=False
When DEBUG is set to False, Django requires you to define the list of allowed hosts.
Step 6: Setting ALLOWED_HOSTS
The ALLOWED_HOSTS setting tells Django which domain names are valid for your site. This prevents HTTP Host header attacks.
Example:
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com', 'localhost']
For testing locally, you can use:
ALLOWED_HOSTS = ['*']
However, using '*' in production is not secure. Always specify exact hostnames for safety.
Step 7: Static and Media Files Configuration
Django does not serve static and media files automatically in production. You need to collect them and serve them using a web server like Nginx or AWS S3.
Configure Static Files in settings.py
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
Run the command below to collect all static files into STATIC_ROOT:
python manage.py collectstatic
This gathers all CSS, JS, and image files from each app into one central location for serving.
Step 8: Using Whitenoise to Serve Static Files (Optional)
If you want Django to serve static files without configuring Nginx initially, use Whitenoise.
Install it:
pip install whitenoise
Then modify your MIDDLEWARE in settings.py:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
...
]
This setup allows Django to serve static files efficiently in a production environment without needing an external web server initially.
Step 9: Configuring Allowed Origins for CORS
If your Django backend serves a frontend (like React or Vue) hosted on a different domain, you must configure CORS (Cross-Origin Resource Sharing).
Install the CORS package:
pip install django-cors-headers
Add it to INSTALLED_APPS:
INSTALLED_APPS = [
...
'corsheaders',
]
Add the middleware:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
...
]
Then configure allowed origins:
CORS_ALLOWED_ORIGINS = [
"https://yourfrontenddomain.com",
]
This ensures secure communication between your frontend and Django backend.
Step 10: Setting Up Logging
Logging helps you monitor errors and track what happens on your server. You should configure Django to log errors to files or external services like Sentry.
Example configuration in settings.py:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': BASE_DIR / 'logs/django_errors.log',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'ERROR',
'propagate': True,
},
},
}
Now all errors will be logged to django_errors.log in the logs directory.
Step 11: Setting Up a Production Web Server (Gunicorn + Nginx)
The Django development server (runserver) is not suitable for production. Instead, you should use Gunicorn or uWSGI with Nginx.
Installing Gunicorn
pip install gunicorn
Run Gunicorn locally to test:
gunicorn myproject.wsgi:application
Configuring Nginx
Nginx acts as a reverse proxy that handles client requests and forwards them to Gunicorn. Example Nginx configuration:
server {
listen 80;
server_name yourdomain.com;
location /static/ {
alias /path/to/your/project/staticfiles/;
}
location /media/ {
alias /path/to/your/project/media/;
}
location / {
proxy_pass http://127.0.0.1:8000;
include proxy_params;
}
}
Restart Nginx after making changes:
sudo systemctl restart nginx
Step 12: Enabling HTTPS with SSL/TLS
Security is paramount. Always serve your site using HTTPS to protect user data. You can use Let’s Encrypt to get free SSL certificates.
Install Certbot:
sudo apt install certbot python3-certbot-nginx
Then obtain a certificate:
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot automatically configures HTTPS in your Nginx server block.
Step 13: Security Best Practices
Here are several essential security configurations you must enable in production.
1. Secure Cookies
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
This ensures cookies are only sent over HTTPS.
2. Use X-Frame, X-Content, and X-XSS Headers
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
3. HTTP Strict Transport Security (HSTS)
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
These settings force browsers to use HTTPS for your site.
4. Disable Clickjacking
X_FRAME_OPTIONS = 'DENY'
5. Hide Django Version Information
Remove the X-Powered-By header from your server to prevent disclosing framework details.
Step 14: Using Caching for Performance
Caching improves response times by storing copies of frequently accessed data.
Example: Using Memcached
Install Memcached and Django integration:
pip install python-memcached
Update your settings:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
You can now use caching in views or templates to reduce database load.
Step 15: Applying Database Migrations
Before running your production server, ensure your database schema is up to date:
python manage.py migrate
Also, collect static files and create a superuser:
python manage.py collectstatic
python manage.py createsuperuser
Step 16: Setting Up Cron Jobs or Celery for Background Tasks
If your application performs background tasks like sending emails or processing reports, use Celery with a broker like Redis.
Install Celery and Redis:
pip install celery redis
Configure Celery in your project’s __init__.py file, and set up Redis to handle background jobs efficiently.
Step 17: Monitoring and Logging Tools
To ensure smooth operation, use monitoring tools to track uptime and performance.
- Sentry – Error tracking and reporting
- Prometheus + Grafana – Metrics monitoring
- ELK Stack (Elasticsearch, Logstash, Kibana) – Centralized logging
These tools help identify performance bottlenecks and production errors quickly.
Step 18: Running Django as a Systemd Service
You can configure Gunicorn to run as a service that restarts automatically on server reboot.
Create a file /etc/systemd/system/gunicorn.service:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/project
ExecStart=/path/to/venv/bin/gunicorn --workers 3 --bind unix:/path/to/your/project.sock myproject.wsgi:application
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl enable gunicorn
sudo systemctl start gunicorn
Step 19: Testing Your Production Setup
Before going live, perform the following checks:
- Is
DEBUGset toFalse? - Are all environment variables loaded correctly?
- Are static files being served correctly?
- Does HTTPS work?
- Are logs being written?
- Is the database connection stable?
Use tools like:
curl -I yourdomain.comto test headerspingandtracerouteto test connectivity- Django’s
checkcommand:
python manage.py check --deploy
This built-in command identifies potential production misconfigurations.
Leave a Reply