# SmoothSchedule Production Deployment Guide ## Prerequisites ### Server Requirements - Ubuntu/Debian Linux server - Minimum 2GB RAM, 20GB disk space - Docker and Docker Compose installed - Domain name pointed to server IP: `smoothschedule.com` - DNS configured with wildcard subdomain: `*.smoothschedule.com` ### Required Accounts/Services - [x] DigitalOcean Spaces (already configured) - Access Key: DO801P4R8QXYMY4CE8WZ - Bucket: smoothschedule - Region: nyc3 - [ ] Email service (optional - Mailgun or SMTP) - [ ] Sentry (optional - error tracking) ## Pre-Deployment Checklist ### 1. DigitalOcean Spaces Setup ```bash # Create the bucket (if not already created) aws --profile do-tor1 s3 mb s3://smoothschedule # Set bucket to public-read for static/media files aws --profile do-tor1 s3api put-bucket-acl \ --bucket smoothschedule \ --acl public-read # Configure CORS (for frontend uploads) cat > cors.json < . git checkout main # Option B: Copy from local machine # From your local machine: # rsync -avz --exclude 'node_modules' --exclude '.venv' --exclude '__pycache__' \ # /home/poduck/Desktop/smoothschedule2/ poduck@smoothschedule.com:~/smoothschedule/ # Navigate to backend cd smoothschedule # Build and start containers docker compose -f docker-compose.production.yml build docker compose -f docker-compose.production.yml up -d # Wait for containers to start sleep 10 # Check logs docker compose -f docker-compose.production.yml logs -f ``` ### Step 3: Database Initialization ```bash # Run migrations docker compose -f docker-compose.production.yml exec django python manage.py migrate # Create public schema (for multi-tenancy) docker compose -f docker-compose.production.yml exec django python manage.py migrate_schemas --shared # Create superuser docker compose -f docker-compose.production.yml exec django python manage.py createsuperuser # Collect static files (uploads to DigitalOcean Spaces) docker compose -f docker-compose.production.yml exec django python manage.py collectstatic --noinput ``` ### Step 4: Create Initial Tenant ```bash # Access Django shell docker compose -f docker-compose.production.yml exec django python manage.py shell # In the shell, create your first business tenant: ``` ```python from core.models import Business from django.contrib.auth import get_user_model User = get_user_model() # Create a business business = Business.objects.create( name="Demo Business", subdomain="demo", schema_name="demo", ) # Verify it was created print(f"Created business: {business.name} at {business.subdomain}.smoothschedule.com") # Create a business owner owner = User.objects.create_user( username="demo_owner", email="owner@demo.com", password="your_password_here", role="owner", business_subdomain="demo" ) print(f"Created owner: {owner.username}") exit() ``` ### Step 5: Deploy Frontend ```bash # On your local machine cd /home/poduck/Desktop/smoothschedule2/frontend # Install dependencies npm install # Build for production npm run build # Upload build files to server rsync -avz dist/ poduck@smoothschedule.com:~/smoothschedule-frontend/ # On the server, set up nginx or serve via backend ``` **Option A: Serve via Django (simpler)** The Django `collectstatic` command already handles static files. For serving the frontend: 1. Copy frontend build to Django static folder 2. Django will serve it via Traefik **Option B: Separate Nginx (recommended for production)** ```bash # Install nginx sudo apt-get update sudo apt-get install -y nginx # Create nginx config sudo nano /etc/nginx/sites-available/smoothschedule ``` ```nginx server { listen 80; server_name smoothschedule.com *.smoothschedule.com; # Frontend (React) location / { root /home/poduck/smoothschedule-frontend; try_files $uri $uri/ /index.html; } # Backend API (proxy to Traefik) location /api { proxy_pass http://localhost:80; 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; } location /admin { proxy_pass http://localhost:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` ```bash # Enable site sudo ln -s /etc/nginx/sites-available/smoothschedule /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` ### Step 6: SSL/HTTPS Setup Traefik is configured to automatically obtain Let's Encrypt SSL certificates. Ensure: 1. DNS is pointed to your server 2. Ports 80 and 443 are accessible 3. Wait for Traefik to obtain certificates (check logs) ```bash # Monitor Traefik logs docker compose -f docker-compose.production.yml logs -f traefik # You should see: # "Certificate obtained for domain smoothschedule.com" ``` ### Step 7: Verify Deployment ```bash # Check all containers are running docker compose -f docker-compose.production.yml ps # Should show: # - django (running) # - postgres (running) # - redis (running) # - traefik (running) # - celeryworker (running) # - celerybeat (running) # - flower (running) # Test API endpoint curl https://smoothschedule.com/api/ # Test admin curl https://smoothschedule.com/admin/ # Access in browser: # https://smoothschedule.com - Main site # https://platform.smoothschedule.com - Platform dashboard # https://demo.smoothschedule.com - Demo business # https://smoothschedule.com:5555 - Flower (Celery monitoring) ``` ## Post-Deployment ### 1. Monitoring ```bash # View logs docker compose -f docker-compose.production.yml logs -f # View specific service logs docker compose -f docker-compose.production.yml logs -f django docker compose -f docker-compose.production.yml logs -f postgres # Monitor Celery tasks via Flower # Access: https://smoothschedule.com:5555 # Login with credentials from .envs/.production/.django ``` ### 2. Backups ```bash # Database backup docker compose -f docker-compose.production.yml exec postgres backup # List backups docker compose -f docker-compose.production.yml exec postgres backups # Restore from backup docker compose -f docker-compose.production.yml exec postgres restore backup_filename.sql.gz ``` ### 3. Updates ```bash # Pull latest code cd ~/smoothschedule/smoothschedule git pull origin main # Rebuild and restart docker compose -f docker-compose.production.yml build docker compose -f docker-compose.production.yml up -d # Run migrations docker compose -f docker-compose.production.yml exec django python manage.py migrate # Collect static files docker compose -f docker-compose.production.yml exec django python manage.py collectstatic --noinput ``` ## Troubleshooting ### SSL Certificate Issues ```bash # Check Traefik logs docker compose -f docker-compose.production.yml logs traefik # Verify DNS is pointing to server dig smoothschedule.com +short # Ensure ports are open sudo ufw allow 80 sudo ufw allow 443 ``` ### Database Connection Issues ```bash # Check PostgreSQL is running docker compose -f docker-compose.production.yml ps postgres # Check database logs docker compose -f docker-compose.production.yml logs postgres # Verify connection docker compose -f docker-compose.production.yml exec django python manage.py dbshell ``` ### Static Files Not Loading ```bash # Verify DigitalOcean Spaces credentials docker compose -f docker-compose.production.yml exec django python manage.py shell >>> from django.conf import settings >>> print(settings.AWS_ACCESS_KEY_ID) >>> print(settings.AWS_STORAGE_BUCKET_NAME) # Re-collect static files docker compose -f docker-compose.production.yml exec django python manage.py collectstatic --noinput # Check Spaces bucket aws --profile do-tor1 s3 ls s3://smoothschedule/static/ aws --profile do-tor1 s3 ls s3://smoothschedule/media/ ``` ### Celery Not Running Tasks ```bash # Check Celery worker logs docker compose -f docker-compose.production.yml logs celeryworker # Access Flower dashboard # https://smoothschedule.com:5555 # Restart Celery docker compose -f docker-compose.production.yml restart celeryworker celerybeat ``` ## Security Checklist - [x] SSL/HTTPS enabled via Let's Encrypt - [x] DJANGO_SECRET_KEY set to random value - [x] Database password set to random value - [x] Flower dashboard password protected - [ ] Firewall configured (UFW or iptables) - [ ] SSH key-based authentication enabled - [ ] Fail2ban installed for brute-force protection - [ ] Regular backups configured - [ ] Sentry error monitoring (optional) ## Performance Optimization 1. **Enable CDN for DigitalOcean Spaces** - In Spaces settings, enable CDN - Update `DJANGO_AWS_S3_CUSTOM_DOMAIN=smoothschedule.nyc3.cdn.digitaloceanspaces.com` 2. **Scale Gunicorn Workers** - Adjust `WEB_CONCURRENCY` in `.envs/.production/.django` - Formula: (2 x CPU cores) + 1 3. **Add Redis Persistence** - Update docker-compose.production.yml redis config - Enable AOF persistence 4. **Database Connection Pooling** - Already configured via `CONN_MAX_AGE=60` ## Maintenance ### Weekly - Review error logs - Check disk space: `df -h` - Monitor Flower dashboard for failed tasks ### Monthly - Update Docker images: `docker compose pull` - Update dependencies: `uv sync` - Review backups ### As Needed - Scale resources (CPU/RAM) - Add more Celery workers - Optimize database queries