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)