11 KiB
11 KiB
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
- 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
# 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 <<EOF
{
"CORSRules": [
{
"AllowedOrigins": ["https://smoothschedule.com", "https://*.smoothschedule.com"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3000
}
]
}
EOF
aws --profile do-tor1 s3api put-bucket-cors \
--bucket smoothschedule \
--cors-configuration file://cors.json
2. DNS Configuration
Configure these DNS records at your domain registrar:
Type Name Value TTL
A smoothschedule.com YOUR_SERVER_IP 300
A *.smoothschedule.com YOUR_SERVER_IP 300
CNAME www smoothschedule.com 300
3. Environment Variables Review
Backend (.envs/.production/.django):
- DJANGO_SECRET_KEY - Set
- DJANGO_ALLOWED_HOSTS - Set to
.smoothschedule.com - DJANGO_AWS_ACCESS_KEY_ID - Set
- DJANGO_AWS_SECRET_ACCESS_KEY - Set
- DJANGO_AWS_STORAGE_BUCKET_NAME - Set to
smoothschedule - DJANGO_AWS_S3_ENDPOINT_URL - Set to
https://nyc3.digitaloceanspaces.com - DJANGO_AWS_S3_REGION_NAME - Set to
nyc3 - MAILGUN_API_KEY - Optional (for email)
- MAILGUN_DOMAIN - Optional (for email)
- SENTRY_DSN - Optional (for error tracking)
Frontend (.env.production):
- VITE_API_URL - Set to
https://smoothschedule.com/api
Deployment Steps
Step 1: Server Preparation
# SSH into production server
ssh poduck@smoothschedule.com
# Install Docker (if not already installed)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# Logout and login again for group changes to take effect
exit
ssh poduck@smoothschedule.com
Step 2: Deploy Backend (Django)
# Create deployment directory
mkdir -p ~/smoothschedule
cd ~/smoothschedule
# Clone the repository (or upload files via rsync/git)
# Option A: Clone from Git
git clone <your-repo-url> .
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
# 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
# Access Django shell
docker compose -f docker-compose.production.yml exec django python manage.py shell
# In the shell, create your first business tenant:
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
# 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:
- Copy frontend build to Django static folder
- Django will serve it via Traefik
Option B: Separate Nginx (recommended for production)
# Install nginx
sudo apt-get update
sudo apt-get install -y nginx
# Create nginx config
sudo nano /etc/nginx/sites-available/smoothschedule
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;
}
}
# 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:
- DNS is pointed to your server
- Ports 80 and 443 are accessible
- Wait for Traefik to obtain certificates (check logs)
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
- SSL/HTTPS enabled via Let's Encrypt
- DJANGO_SECRET_KEY set to random value
- Database password set to random value
- 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
-
Enable CDN for DigitalOcean Spaces
- In Spaces settings, enable CDN
- Update
DJANGO_AWS_S3_CUSTOM_DOMAIN=smoothschedule.nyc3.cdn.digitaloceanspaces.com
-
Scale Gunicorn Workers
- Adjust
WEB_CONCURRENCYin.envs/.production/.django - Formula: (2 x CPU cores) + 1
- Adjust
-
Add Redis Persistence
- Update docker-compose.production.yml redis config
- Enable AOF persistence
-
Database Connection Pooling
- Already configured via
CONN_MAX_AGE=60
- Already configured via
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