Production Deployment¶
Environment Variables¶
Set all required environment variables for production:
# Django
DJANGO_SECRET_KEY=your-secret-key-here
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
# Database (PostgreSQL recommended)
DB_ENGINE=django.db.backends.postgresql
DB_NAME=subscription_db
DB_USER=postgres
DB_PASSWORD=
DB_HOST=localhost
DB_PORT=5432
# Celery / Redis
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/0
# Midtrans (PRODUCTION keys)
MIDTRANS_SERVER_KEY=
MIDTRANS_CLIENT_KEY=
MIDTRANS_MERCHANT_ID=
MIDTRANS_IS_PRODUCTION=True
MIDTRANS_NOTIFICATION_URL=https://yourdomain.com/api/subscriptions/webhook/notification/
Warning
MIDTRANS_IS_PRODUCTION=True switches the API base URL from sandbox to api.midtrans.com. Only use this with production keys from Midtrans Dashboard.
Production Checklist¶
DEBUG=FalseStrong
SECRET_KEY(not the default)ALLOWED_HOSTSset to your domain(s)PostgreSQL database (not SQLite)
Redis for Celery broker
HTTPS enabled
Midtrans production keys configured
MIDTRANS_NOTIFICATION_URLis publicly accessible via HTTPSCelery worker running
Celery beat running with
DatabaseSchedulersetup_periodic_taskscommand executedStatic files collected (
collectstatic)Gunicorn or uWSGI as application server
Nginx as reverse proxy
Gunicorn¶
pip install gunicorn
gunicorn config.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 4 \
--timeout 120
Systemd Services¶
Django (Gunicorn)¶
# /etc/systemd/system/django-subscription.service
[Unit]
Description=Django Subscription App
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/django-subscription-midtrans
Environment="PATH=/opt/django-subscription-midtrans/.venv/bin"
EnvironmentFile=/opt/django-subscription-midtrans/.env
ExecStart=/opt/django-subscription-midtrans/.venv/bin/gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 4
Restart=always
[Install]
WantedBy=multi-user.target
Celery Worker¶
# /etc/systemd/system/celery-worker.service
[Unit]
Description=Celery Worker
After=network.target redis.service
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/django-subscription-midtrans
Environment="PATH=/opt/django-subscription-midtrans/.venv/bin"
EnvironmentFile=/opt/django-subscription-midtrans/.env
ExecStart=/opt/django-subscription-midtrans/.venv/bin/celery -A config worker -l info
Restart=always
[Install]
WantedBy=multi-user.target
Celery Beat¶
# /etc/systemd/system/celery-beat.service
[Unit]
Description=Celery Beat Scheduler
After=network.target redis.service
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/django-subscription-midtrans
Environment="PATH=/opt/django-subscription-midtrans/.venv/bin"
EnvironmentFile=/opt/django-subscription-midtrans/.env
ExecStart=/opt/django-subscription-midtrans/.venv/bin/celery -A config beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
Restart=always
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl enable django-subscription celery-worker celery-beat
sudo systemctl start django-subscription celery-worker celery-beat
Nginx Configuration¶
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location /static/ {
alias /opt/django-subscription-midtrans/staticfiles/;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Database Migrations¶
Always run migrations before deploying:
python manage.py migrate
python manage.py collectstatic --noinput
python manage.py setup_periodic_tasks
Monitoring¶
Logging¶
Configure Django logging for the subscriptions and subscriptions.midtrans loggers:
LOGGING = {
"version": 1,
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "/var/log/django-subscription/app.log",
},
},
"loggers": {
"subscriptions": {"handlers": ["file"], "level": "INFO"},
"subscriptions.midtrans": {"handlers": ["file"], "level": "DEBUG"},
},
}
Celery Monitoring¶
Use Flower for Celery task monitoring:
pip install flower
celery -A config flower --port=5555