This guide covers deploying The Inventory backend API to production environments.
Before deploying to production, ensure:
ALLOWED_HOSTS configureddocker build -t the_inventory:latest .
docker run -p 8000:8000 \
-e SECRET_KEY="your-secret-key" \
-e ALLOWED_HOSTS="localhost,127.0.0.1" \
-e DATABASE_URL="postgresql://user:pass@db:5432/inventory" \
the_inventory:latest
# Tag image
docker tag the_inventory:latest your-registry/the_inventory:latest
# Push to registry
docker push your-registry/the_inventory:latest
Create docker-compose.yml:
version: '3.8'
services:
db:
image: postgres:15
environment:
POSTGRES_DB: inventory
POSTGRES_USER: inventory_user
POSTGRES_PASSWORD: secure_password
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:7
ports:
- "6379:6379"
web:
build: .
command: gunicorn the_inventory.wsgi:application --bind 0.0.0.0:8000
environment:
DEBUG: "False"
SECRET_KEY: "your-secret-key"
ALLOWED_HOSTS: "localhost,127.0.0.1"
DATABASE_URL: "postgresql://inventory_user:secure_password@db:5432/inventory"
REDIS_URL: "redis://redis:6379/0"
ports:
- "8000:8000"
depends_on:
- db
- redis
volumes:
- ./src:/app/src
volumes:
postgres_data:
Run with:
docker-compose up -d
the_inventory repositoryBasic Settings:
the-inventory-apiPython 3pip install -r requirements.txt && python src/manage.py collectstatic --noinputgunicorn the_inventory.wsgi:application --bind 0.0.0.0:8000 --chdir srcIn Render dashboard, add these environment variables:
Required Variables:
DEBUG=False
DJANGO_SETTINGS_MODULE=the_inventory.settings.production
SECRET_KEY=<generate-and-paste>
ALLOWED_HOSTS=your-service.onrender.com
DATABASE_URL=<PostgreSQL-connection-string>
Critical for JWT Authentication (MUST SET - prevents 401 errors):
CORS_ALLOWED_ORIGINS=https://your-frontend.vercel.app
FRONTEND_URL=https://your-frontend.vercel.app
CSRF_TRUSTED_ORIGINS=https://your-frontend.vercel.app
JWT Cookie Configuration:
JWT_COOKIE_SECURE=true
JWT_COOKIE_SAMESITE=Lax
JWT_COOKIE_DOMAIN=
Optional but Recommended:
REDIS_URL=<Redis-connection-string>
DJANGO_LOG_LEVEL=INFO
AUTO_SEED_DATABASE=false
⚠️ Important: If you skip the “Critical for JWT Authentication” variables, users will get 401 Unauthorized errors after login. See Troubleshooting Guide for details.
DATABASE_URL environment variableREDIS_URL environment variableClick “Create Web Service” — Render will automatically deploy.
After first deployment, run migrations:
# Via Render Shell
python src/manage.py migrate
python src/manage.py createsuperuser
apiVersion: v1
kind: ConfigMap
metadata:
name: inventory-config
data:
DEBUG: "False"
DJANGO_SETTINGS_MODULE: "the_inventory.settings.production"
ALLOWED_HOSTS: "api.example.com"
FRONTEND_URL: "https://app.example.com"
CORS_ALLOWED_ORIGINS: "https://app.example.com"
apiVersion: v1
kind: Secret
metadata:
name: inventory-secrets
type: Opaque
stringData:
SECRET_KEY: "your-secret-key"
DATABASE_URL: "postgresql://user:pass@db:5432/inventory"
REDIS_URL: "redis://redis:6379/0"
apiVersion: apps/v1
kind: Deployment
metadata:
name: inventory-api
spec:
replicas: 3
selector:
matchLabels:
app: inventory-api
template:
metadata:
labels:
app: inventory-api
spec:
containers:
- name: api
image: your-registry/the_inventory:latest
ports:
- containerPort: 8000
envFrom:
- configMapRef:
name: inventory-config
- secretRef:
name: inventory-secrets
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /api/v1/
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/v1/
port: 8000
initialDelaySeconds: 10
periodSeconds: 5
apiVersion: v1
kind: Service
metadata:
name: inventory-api-service
spec:
selector:
app: inventory-api
ports:
- protocol: TCP
port: 80
targetPort: 8000
type: LoadBalancer
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
| Variable | Example | Description |
|---|---|---|
SECRET_KEY |
django-insecure-... |
Django secret key (generate new) |
ALLOWED_HOSTS |
api.example.com |
Allowed hostnames |
DATABASE_URL |
postgresql://user:pass@host/db |
PostgreSQL connection |
DEBUG |
False |
Disable debug mode in production |
| Variable | Example | Description |
|---|---|---|
REDIS_URL |
redis://host:6379/0 |
Redis cache connection |
FRONTEND_URL |
https://app.example.com |
Frontend URL for redirects |
CORS_ALLOWED_ORIGINS |
https://app.example.com |
Frontend CORS origin |
EMAIL_HOST |
smtp.gmail.com |
SMTP server |
EMAIL_HOST_USER |
noreply@example.com |
SMTP username |
EMAIL_HOST_PASSWORD |
app-password |
SMTP password |
See Environment Variables for complete reference.
On Ubuntu/Debian:
sudo apt-get install postgresql postgresql-contrib
On macOS:
brew install postgresql
sudo -u postgres psql
CREATE DATABASE inventory;
CREATE USER inventory_user WITH PASSWORD 'secure_password';
ALTER ROLE inventory_user SET client_encoding TO 'utf8';
ALTER ROLE inventory_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE inventory_user SET default_transaction_deferrable TO on;
ALTER ROLE inventory_user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE inventory TO inventory_user;
\q
postgresql://inventory_user:secure_password@localhost:5432/inventory
cd src
python manage.py migrate
python manage.py createsuperuser
View logs from your deployment platform:
Render:
# Via Render dashboard → Logs tab
Kubernetes:
kubectl logs -f deployment/inventory-api
Monitor PostgreSQL performance:
# Connect to database
psql postgresql://user:pass@host/inventory
# Check active connections
SELECT * FROM pg_stat_activity;
# Check slow queries
SELECT query, calls, mean_time FROM pg_stat_statements ORDER BY mean_time DESC;
Set up monitoring for:
Configure alerts for:
PostgreSQL Backups:
# Daily backup script
#!/bin/bash
BACKUP_DIR="/backups/inventory"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
pg_dump postgresql://user:pass@host/inventory > $BACKUP_DIR/inventory_$TIMESTAMP.sql
gzip $BACKUP_DIR/inventory_$TIMESTAMP.sql
Schedule with cron:
0 2 * * * /path/to/backup-script.sh
pg_dump postgresql://user:pass@host/inventory > inventory_backup.sql
psql postgresql://user:pass@host/inventory < inventory_backup.sql
Use your cloud provider’s backup service:
Render automatically provides SSL certificates. Your service is accessible at:
https://your-service.onrender.com
Use Certbot to get free SSL certificates:
sudo apt-get install certbot python3-certbot-nginx
sudo certbot certonly --standalone -d api.example.com
Configure Nginx to use the certificate:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location / {
proxy_pass http://localhost:8000;
}
}
Error: could not connect to server
Solution:
DATABASE_URL is correct404 Not Found for /static/...
Solution:
python src/manage.py collectstatic --noinput
Error: SECRET_KEY is not set
Solution: Generate and set SECRET_KEY:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
See Troubleshooting Guide for more help.
The Gunicorn worker count can be configured using the GUNICORN_WORKERS environment variable.
By default, the application uses 4 workers.
Example:
GUNICORN_WORKERS=4
For smaller deployments, use fewer workers:
GUNICORN_WORKERS=1
For larger deployments, increase the worker count based on CPU and memory:
GUNICORN_WORKERS=8