In this final part of our series, we'll prepare our Project Budget Manager for production deployment. We'll cover security configurations, performance optimizations, and deployment steps.
Production Settings
- Update config/settings/production.py with production-specific settings:
from .base import *
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
# SECURITY WARNING: configure the secret key for production
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
# Database configuration
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT', '3306'),
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8mb4',
}
}
}
# Email settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = os.environ.get('EMAIL_HOST', 'smtp.gmail.com')
EMAIL_PORT = int(os.environ.get('EMAIL_PORT', 587))
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', EMAIL_HOST_USER)
# Security settings
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
# Static files configuration
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# Enable WhiteNoise for static file serving
MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Site settings
SITE_ID = 1
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
USE_X_FORWARDED_HOST = True
Environment Variables
Create a production .env file template (.env.example):
# Django settings
DJANGO_SETTINGS_MODULE=config.settings.production
DJANGO_SECRET_KEY=your-secret-key-here
ALLOWED_HOSTS=your-domain.com,www.your-domain.com
# Database settings
DB_NAME=budget_db
DB_USER=budget_user
DB_PASSWORD=your-secure-password
DB_HOST=localhost
DB_PORT=3306
# Email settings
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-specific-password
DEFAULT_FROM_EMAIL=your-email@gmail.com
# Security settings
SECURE_SSL_REDIRECT=True
SESSION_COOKIE_SECURE=True
CSRF_COOKIE_SECURE=True
Production Dependencies
Update requirements.txt with production dependencies:
Django==5.0.2
django-allauth==0.61.1
django-crispy-forms==2.3
mysqlclient==2.2.4
whitenoise==6.9.0
python-dotenv==1.0.1
gunicorn==21.2.0
Setting Up MySQL Database
- Install MySQL server:
sudo apt update
sudo apt install mysql-server
- Create database and user:
CREATE DATABASE budget_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'budget_user'@'localhost' IDENTIFIED BY 'your-secure-password';
GRANT ALL PRIVILEGES ON budget_db.* TO 'budget_user'@'localhost';
FLUSH PRIVILEGES;
Nginx Configuration
- Install Nginx:
sudo apt install nginx
- Create Nginx configuration (/etc/nginx/sites-available/project-budget):
server {
listen 80;
server_name your-domain.com www.your-domain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /path/to/your/project;
}
location /media/ {
root /path/to/your/project;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
- Enable the site:
sudo ln -s /etc/nginx/sites-available/project-budget /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
Gunicorn Service
- Create a systemd service file (/etc/systemd/system/gunicorn.service):
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=your-user
Group=www-data
WorkingDirectory=/path/to/your/project
ExecStart=/path/to/your/venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
config.wsgi:application
[Install]
WantedBy=multi-user.target
- Create socket file (/etc/systemd/system/gunicorn.socket):
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
- Start and enable the service:
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
SSL Certificate with Let's Encrypt
- Install Certbot:
sudo apt install certbot python3-certbot-nginx
- Obtain SSL certificate:
sudo certbot --nginx -d your-domain.com -d www.your-domain.com
Deployment Checklist
- Prepare the environment:
# Create and activate virtual environment
python -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
- Set up the database:
python manage.py migrate
python manage.py createsuperuser
- Collect static files:
python manage.py collectstatic --noinput
- Set up environment variables:
cp .env.example .env
# Edit .env with your production values
- Test the application:
python manage.py check --deploy
Monitoring and Maintenance
- Set up logging in production settings:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': '/path/to/django-error.log',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'ERROR',
'propagate': True,
},
},
}
- Regular maintenance tasks:
# Backup database
mysqldump -u budget_user -p budget_db > backup.sql
# Check for updates
pip list --outdated
# Monitor logs
tail -f /path/to/django-error.log
Performance Optimization Tips
- Enable caching:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
}
}
- Use database connection pooling:
DATABASES = {
'default': {
# ... other settings ...
'CONN_MAX_AGE': 60,
}
}
Resources
This article is part of the "Building a Project Budget Manager with Django" series. Check out Part 1, Part 2, and Part 3 if you haven't already!
Top comments (0)