Add comprehensive production deployment manual guide

This commit is contained in:
poduck
2025-11-30 20:13:19 -05:00
parent 2b321aef57
commit b958f9368b

602
PRODUCTION_DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,602 @@
# SmoothSchedule - Production Deployment Manual
Complete step-by-step guide for manually deploying SmoothSchedule from scratch on a production server. This guide is useful when you need to reset the entire production deployment or troubleshoot deployment issues.
## Table of Contents
1. [Prerequisites](#prerequisites)
2. [Complete Fresh Deployment](#complete-fresh-deployment)
3. [Docker Build & Startup](#docker-build--startup)
4. [Database Initialization](#database-initialization)
5. [Static Files & Migrations](#static-files--migrations)
6. [Verification Steps](#verification-steps)
7. [Troubleshooting](#troubleshooting)
---
## Prerequisites
### Required on Production Server
```bash
# Check these are installed and running
docker --version # Docker 20.10+
docker compose --version # Docker Compose 2.0+
```
### Required Locally (Before Deployment)
1. All code changes committed to git (`main` branch)
2. All missing files added to git and pushed
3. Production environment variables backed up locally
4. `.envs/.production/` directory exists with proper credentials
---
## Complete Fresh Deployment
### Step 1: Save Production Environment Variables Locally
**On your local development machine:**
```bash
# Backup current production environment variables
scp poduck@smoothschedule.com:~/smoothschedule/smoothschedule/.envs/.production/.django \
/tmp/production_django_env_backup
scp poduck@smoothschedule.com:~/smoothschedule/smoothschedule/.envs/.production/.postgres \
/tmp/production_postgres_env_backup
```
### Step 2: Prepare & Commit All Code Changes Locally
**On your local development machine:**
```bash
cd /home/poduck/Desktop/smoothschedule2
# Check for any missing files
git status
# Add all changes and new files
git add -A
# Review staged changes
git diff --cached
# Commit changes
git commit -m "Production deployment: Add missing files and config updates"
# Push to main branch
git push origin main
```
### Step 3: Bring Down Production Containers
**SSH into production server:**
```bash
ssh poduck@smoothschedule.com
cd ~/smoothschedule/smoothschedule
# Stop all containers (preserves volumes)
docker compose -f docker-compose.production.yml down
# Or to completely reset and remove volumes (careful!):
docker compose -f docker-compose.production.yml down -v
```
### Step 4: Remove Production Codebase
**On production server:**
```bash
cd ~
# Remove everything
rm -rf smoothschedule
```
### Step 5: Pull Fresh Code from Git
**On production server:**
```bash
cd ~
# Clone the repository
git clone https://git.talova.net/poduck/smoothschedule.git smoothschedule
cd smoothschedule
```
**Note:** If git authentication fails, configure credentials on the server:
```bash
git config --global user.email "poduck@smoothschedule.com"
git config --global user.name "Poduck"
# Or store credentials
git credential approve
# Then paste: protocol=https
# host=git.talova.net
# username=poduck
# password=chaff/starry
```
### Step 6: Restore Production Environment Variables
**On production server:**
```bash
cd ~/smoothschedule/smoothschedule
# Create the .envs/.production directory if it doesn't exist
mkdir -p .envs/.production
# Restore from backups on local machine or recreate them
# Option A: Use SCP to copy from local machine
scp /tmp/production_django_env_backup poduck@smoothschedule.com:~/smoothschedule/smoothschedule/.envs/.production/.django
scp /tmp/production_postgres_env_backup poduck@smoothschedule.com:~/smoothschedule/smoothschedule/.envs/.production/.postgres
# Option B: Manually recreate the files on the production server
# (see Environment Variables section below)
```
---
## Docker Build & Startup
### Step 7: Build Docker Images
**On production server:**
```bash
cd ~/smoothschedule/smoothschedule
# Build all production Docker images
docker compose -f docker-compose.production.yml build
```
**Expected output:**
```
✓ Successfully built:
- smoothschedule_production_django
- smoothschedule_production_celeryworker
- smoothschedule_production_celerybeat
- smoothschedule_production_flower
- smoothschedule_production_postgres
- smoothschedule_production_traefik
- smoothschedule-awscli
```
### Step 8: Start Containers
**On production server:**
```bash
cd ~/smoothschedule/smoothschedule
# Start all containers in detached mode
docker compose -f docker-compose.production.yml up -d
# Wait for services to stabilize (10-15 seconds)
sleep 15
# Check container status
docker compose -f docker-compose.production.yml ps
```
**Expected status:** All containers should be `Up` or `Healthy`
---
## Database Initialization
### Step 9: Run Database Migrations
**On production server:**
The application uses django-tenants for multi-tenant support. Migrations must be run in this order:
```bash
cd ~/smoothschedule/smoothschedule
# 1. Migrate the public/shared schema (all shared apps)
docker compose -f docker-compose.production.yml exec -T django \
python manage.py migrate_schemas --shared
# Expected output should show multiple migrations applied to "public" schema
```
**If you get "service django is not running":**
The Django container may not be fully started. Wait a bit longer:
```bash
sleep 30 # Wait for Django to initialize
docker compose -f docker-compose.production.yml exec -T django \
python manage.py migrate_schemas --shared
```
---
## Static Files & Migrations
### Step 10: Collect Static Files
**On production server:**
```bash
cd ~/smoothschedule/smoothschedule
docker compose -f docker-compose.production.yml exec -T django \
python manage.py collectstatic --noinput
```
This collects all static files (CSS, JS, images) and uploads them to:
- **Local filesystem:** `smoothschedule/staticfiles/`
- **DigitalOcean Spaces/S3:** Configured via `DJANGO_AWS_*` environment variables
### Step 11: Create Superuser (First Time Only)
**On production server, if this is a fresh installation:**
```bash
cd ~/smoothschedule/smoothschedule
docker compose -f docker-compose.production.yml exec django \
python manage.py createsuperuser
# Follow the prompts to create the admin user
```
### Step 12: Create Initial Tenant (First Time Only)
**On production server, if you need a demo tenant:**
```bash
cd ~/smoothschedule/smoothschedule
docker compose -f docker-compose.production.yml exec django python manage.py shell
```
Then in the Django shell:
```python
from core.models import Tenant, Domain
from django.utils.text import slugify
# Create a tenant
tenant = Tenant.objects.create(
name="Demo Company",
slug="demo",
is_free_trial=False,
is_temporary=False,
)
# Create a domain for the tenant
Domain.objects.create(
domain="demo.smoothschedule.com",
tenant=tenant,
)
print(f"Created tenant: {tenant.name} with domain: demo.smoothschedule.com")
exit()
```
---
## Verification Steps
### Step 13: Verify All Services Are Running
```bash
cd ~/smoothschedule/smoothschedule
# Check container status
docker compose -f docker-compose.production.yml ps
# View logs for any errors
docker compose -f docker-compose.production.yml logs --tail=50
# Check specific service logs
docker compose -f docker-compose.production.yml logs django --tail=30
docker compose -f docker-compose.production.yml logs postgres --tail=30
```
### Step 14: Test API Endpoints
**From your local machine:**
```bash
# Test the backend API
curl -s "https://smoothschedule.com/api/health/" | jq
# Test tenant access
curl -s "https://demo.smoothschedule.com/api/resources/" | jq
# Test platform admin
curl -s "https://platform.smoothschedule.com/api/admin/businesses/" | jq
```
### Step 15: Verify Nginx Frontend
The frontend should be accessible at:
- **Main site:** `https://smoothschedule.com`
- **Platform dashboard:** `https://platform.smoothschedule.com`
- **Tenant subdomain:** `https://demo.smoothschedule.com`
---
## Environment Variables Reference
### Django Configuration (`.envs/.production/.django`)
```bash
# Security & Secrets
DJANGO_SECRET_KEY=your-secret-key-here
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=smoothschedule.com,platform.smoothschedule.com,*.smoothschedule.com
# Admin & URLs
DJANGO_ADMIN_URL=<random-slug>/
FRONTEND_URL=https://platform.smoothschedule.com
PLATFORM_BASE_URL=https://platform.smoothschedule.com
# Celery & Redis
REDIS_URL=redis://redis:6379/0
CELERY_BROKER_URL=redis://redis:6379/0
# AWS/DigitalOcean Spaces (for media storage)
DJANGO_AWS_ACCESS_KEY_ID=your-access-key
DJANGO_AWS_SECRET_ACCESS_KEY=your-secret-key
DJANGO_AWS_STORAGE_BUCKET_NAME=smoothschedule
DJANGO_AWS_S3_ENDPOINT_URL=https://nyc3.digitaloceanspaces.com
DJANGO_AWS_S3_REGION_NAME=nyc3
DJANGO_AWS_S3_CUSTOM_DOMAIN=smoothschedule.nyc3.digitaloceanspaces.com
# Email Configuration (optional)
MAILGUN_API_KEY=your-mailgun-key
MAILGUN_DOMAIN=mg.smoothschedule.com
# SSL/Security
DJANGO_SECURE_SSL_REDIRECT=True
DJANGO_SECURE_HSTS_SECONDS=60
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=True
DJANGO_SECURE_HSTS_PRELOAD=True
DJANGO_SESSION_COOKIE_SECURE=True
DJANGO_CSRF_COOKIE_SECURE=True
# Sentry (optional - error tracking)
SENTRY_DSN=
SENTRY_ENVIRONMENT=production
SENTRY_TRACES_SAMPLE_RATE=0.1
```
### PostgreSQL Configuration (`.envs/.production/.postgres`)
```bash
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=smoothschedule
POSTGRES_USER=<random-username>
POSTGRES_PASSWORD=<random-secure-password>
```
---
## Troubleshooting
### Django Container Won't Start
**Symptom:** `docker compose ps` shows Django as exited
**Solution:**
```bash
cd ~/smoothschedule/smoothschedule
# View full error logs
docker compose -f docker-compose.production.yml logs django --tail=100
# Check if database is accessible
docker compose -f docker-compose.production.yml logs postgres --tail=20
# Restart Django after fixing the issue
docker compose -f docker-compose.production.yml restart django
```
### Migration Fails with "role does not exist"
**Symptom:** Error when running `migrate_schemas --shared`:
```
FATAL: role "postgres" does not exist
```
**Solution:** The database volume is corrupted. Reset and restart:
```bash
cd ~/smoothschedule/smoothschedule
# Stop and remove all volumes
docker compose -f docker-compose.production.yml down -v
# Restart (this will recreate the database)
docker compose -f docker-compose.production.yml up -d
# Wait for database to initialize (30 seconds)
sleep 30
# Try migrations again
docker compose -f docker-compose.production.yml exec -T django \
python manage.py migrate_schemas --shared
```
### Cannot Connect to Production Server
**Check SSH access:**
```bash
ssh poduck@smoothschedule.com "echo 'Connection successful'"
```
**If that fails:**
- Verify your SSH key is authorized on the server
- Check firewall rules allow SSH (port 22)
- Verify DNS resolves `smoothschedule.com` to the correct IP
### Traefik Certificate Issues
**Symptom:** SSL certificate errors, HTTP redirects failing
**Solution:**
```bash
cd ~/smoothschedule/smoothschedule
# Check Traefik logs
docker compose -f docker-compose.production.yml logs traefik --tail=50
# Restart Traefik to request new certificates
docker compose -f docker-compose.production.yml restart traefik
# Wait for Let's Encrypt to issue certificates (5-10 minutes)
# Check via: https://smoothschedule.com (should show valid cert)
```
### Frontend Not Loading
**Verify nginx container is running:**
```bash
# Check if nginx image was built
docker images | grep smoothschedule
# If missing, rebuild
docker compose -f docker-compose.production.yml build nginx
# Restart the service
docker compose -f docker-compose.production.yml restart
# Check logs
docker logs $(docker ps -q --filter "name=nginx")
```
---
## Quick Reference Commands
```bash
# SSH to production server
ssh poduck@smoothschedule.com
# Navigate to project
cd ~/smoothschedule/smoothschedule
# View all container logs
docker compose -f docker-compose.production.yml logs -f
# View Django logs only
docker compose -f docker-compose.production.yml logs django -f --tail=100
# Stop all containers
docker compose -f docker-compose.production.yml down
# Start all containers
docker compose -f docker-compose.production.yml up -d
# Restart a specific service
docker compose -f docker-compose.production.yml restart django
# Run a Django management command
docker compose -f docker-compose.production.yml exec -T django python manage.py <command>
# Access Django shell
docker compose -f docker-compose.production.yml exec django python manage.py shell
# Create a database backup
docker compose -f docker-compose.production.yml exec -T postgres \
pg_dump -U $POSTGRES_USER smoothschedule > backup.sql
# Execute arbitrary SQL
docker compose -f docker-compose.production.yml exec -T postgres \
psql -U $POSTGRES_USER smoothschedule -c "SELECT version();"
# Check Docker resource usage
docker stats
```
---
## Advanced: Rollback Procedure
If a deployment fails catastrophically:
```bash
# 1. Stop everything
cd ~/smoothschedule/smoothschedule
docker compose -f docker-compose.production.yml down
# 2. Restore from database backup (if available)
docker compose -f docker-compose.production.yml exec -T postgres \
psql -U $POSTGRES_USER smoothschedule < backup.sql
# 3. Checkout previous git commit
cd ~/smoothschedule
git checkout <previous-commit-hash>
# 4. Rebuild and restart
cd smoothschedule
docker compose -f docker-compose.production.yml build
docker compose -f docker-compose.production.yml up -d
```
---
## Monitoring Checklist
After deployment, monitor these for 24 hours:
- [ ] No error logs in `docker compose logs django`
- [ ] API endpoints respond with 200 status
- [ ] SSL certificates are valid (https://smoothschedule.com)
- [ ] Frontend loads without console errors
- [ ] Tenant subdomains work correctly
- [ ] Static files are being served (CSS, JS load)
- [ ] Background tasks execute (check Celery worker logs)
- [ ] No database connection errors
---
## Important Notes
1. **Always backup before major changes:**
- Database: `pg_dump`
- Environment variables: Copy `.envs/.production/` locally
- Code: Git commits
2. **Never modify code on production directly:**
- Change code locally → Git push → Production git pull
- Only edit `.env` files directly on production
3. **Multi-Tenancy Considerations:**
- Each tenant gets a separate PostgreSQL schema
- Migrations apply to "public" schema (shared) first
- Tenant migrations happen automatically on first request to new tenant
4. **Docker Compose File:**
- Always use `-f docker-compose.production.yml` for production
- Never use `-f docker-compose.local.yml` on production
5. **Persistence:**
- Database: `production_postgres_data` volume
- Redis: `production_redis_data` volume
- Traefik certs: `production_traefik` volume
- These are preserved when using `down` (not `down -v`)
---
**Last Updated:** December 2025
**Deployment Version:** Manual v1.0