Deployment
This guide covers deploying Morning Drive to production environments.
./dev.sh. This page covers production deployment.
Docker Hub Deployment (Recommended)
The recommended approach is to build and push to Docker Hub, then pull the image on your production server. This method:
- Keeps your production server clean (no build tools needed)
- Enables easy rollbacks to previous versions
- Auto-restarts on server reboot
Step 1: Build & Push (Development Machine)
On your development machine, build and push the Docker image:
cd backend
# Build and push with a version tag
export DOCKER_USERNAME=usaiinc
./scripts/build-and-push.sh v1.0.0
The script will:
- Build the Docker image for linux/amd64
- Tag it with your version and "latest"
- Push to Docker Hub
usaiinc (created via GitHub authentication). Run docker login to authenticate before pushing.
Step 2: Deploy (Production Server)
Use the deploy script to copy files to your server:
cd backend
# Deploy to altair (default)
./scripts/deploy-to-server.sh
# Or specify a different SSH host
./scripts/deploy-to-server.sh myserver
The script copies docker-compose.prod.yml, .env.prod.example, and the assets/ folder to ~/morning-drive on the target server.
altair. Set up your SSH config in ~/.ssh/config for passwordless access.
After running the script, SSH to your server and configure the environment:
# SSH to your server
ssh altair
cd ~/morning-drive
# Edit .env with your API keys
nano .env
Required .env Configuration
# API Keys
ANTHROPIC_API_KEY=sk-ant-xxxxx
ELEVENLABS_API_KEY=xxxxx
# Admin password - CHANGE THIS!
ADMIN_PASSWORD=your-secure-password
Step 3: Start Services
# Pull and start (will auto-restart on boot)
docker compose -f docker-compose.prod.yml up -d
# View logs
docker compose -f docker-compose.prod.yml logs -f
# Check status
docker compose -f docker-compose.prod.yml ps
restart: always, so services automatically start when the server boots.
Updating to a New Version
# On development machine: build and push new version
./scripts/build-and-push.sh v1.1.0
# On production server: pull and restart
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
Alternative: Build on Production Server
If you prefer to build directly on the production server instead of using Docker Hub:
cd backend
cp .env.example .env
nano .env # Add your API keys
docker compose -f docker-compose.yml up -d --build
Note: For production, explicitly specify -f docker-compose.yml to skip the development override.
Services Overview
| Service | Port | Description |
|---|---|---|
| morning-drive | 5000 | Main FastAPI application |
| minio | 9000, 9001 | S3-compatible storage for music |
| scheduler | - | Optional background job scheduler |
Environment Variables
| Variable | Required | Description |
|---|---|---|
ANTHROPIC_API_KEY | Yes | Claude API key for content generation |
ELEVENLABS_API_KEY | Yes | ElevenLabs API key for TTS |
ADMIN_PASSWORD | Yes | Password for admin panel access |
IMAGE_TAG | No | Docker image tag (default: latest) |
MINIO_ACCESS_KEY | No | MinIO access key (default: minioadmin) |
MINIO_SECRET_KEY | No | MinIO secret key (default: minioadmin) |
ELEVENLABS_CUSTOM_VOICE_IDS | No | Comma-separated custom voice IDs |
Port Configuration
The production setup exposes the API on port 5000 (mapped to internal port 8000). This is configured for use with Cloudflare Tunnels.
Running the Scheduler
The scheduler service handles automatic briefing generation at scheduled times:
# Start with scheduler enabled
docker-compose --profile with-scheduler up -d
Production Considerations
Reverse Proxy Setup (nginx)
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
SSL/TLS
Use Let's Encrypt with Certbot for free SSL certificates:
sudo certbot --nginx -d your-domain.com
Persistent Storage
The Docker setup uses named volumes for data persistence:
morning-drive-data- SQLite database and generated audio filesmorning-drive-minio-data- Uploaded music files
Data persists across container restarts and updates. Deploying new compose files will NOT overwrite your data. Volumes are only deleted if you explicitly run docker compose down -v.
Syncing Music Library
To sync music pieces from your local development environment to production:
cd backend
./scripts/sync-music-to-server.sh
This script exports music files from local MinIO and database records, then imports them into production. It adds/updates files without deleting existing production data.
Health Checks
Monitor your deployment with the health endpoint:
curl http://localhost:8000/health
# {"status": "healthy", "service": "morning-drive"}
Or use the Admin Health Dashboard for a detailed view of all services.
Managing the Deployment
# View running services
docker compose -f docker-compose.prod.yml ps
# View logs
docker compose -f docker-compose.prod.yml logs -f
# Restart services
docker compose -f docker-compose.prod.yml restart
# Stop all services
docker compose -f docker-compose.prod.yml down
# Stop and remove volumes (WARNING: deletes all data)
docker compose -f docker-compose.prod.yml down -v
Troubleshooting
| Issue | Solution |
|---|---|
| Container won't start | Check logs: docker compose logs morning-drive |
| Can't pull image | Verify DOCKER_USERNAME in .env matches your Docker Hub account |
| MinIO connection failed | Ensure MinIO container is healthy: docker compose ps |
| API keys not working | Check .env file has no quotes around values |