450 lines
11 KiB
Markdown
450 lines
11 KiB
Markdown
# 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 <<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`):
|
|
- [x] DJANGO_SECRET_KEY - Set
|
|
- [x] DJANGO_ALLOWED_HOSTS - Set to `.smoothschedule.com`
|
|
- [x] DJANGO_AWS_ACCESS_KEY_ID - Set
|
|
- [x] DJANGO_AWS_SECRET_ACCESS_KEY - Set
|
|
- [x] DJANGO_AWS_STORAGE_BUCKET_NAME - Set to `smoothschedule`
|
|
- [x] DJANGO_AWS_S3_ENDPOINT_URL - Set to `https://nyc3.digitaloceanspaces.com`
|
|
- [x] 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`):
|
|
- [x] VITE_API_URL - Set to `https://smoothschedule.com/api`
|
|
|
|
## Deployment Steps
|
|
|
|
### Step 1: Server Preparation
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```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
|