Skip to content

Docker Compose File Structure

Last Updated: February 24, 2026

Overview

Uplink uses Docker Compose override files to maintain clean separation between development and production configurations while sharing common base settings.

File Structure

uplink/
├── docker-compose.yml           # Base configuration (shared)
├── docker-compose.dev.yml       # Development overrides
├── docker-compose.prod.yml      # Production overrides
├── docker-compose-old.yml       # Backup of previous monolithic config
└── docker-compose.yml.backup    # Another backup

How It Works

Base File (docker-compose.yml)

Contains shared configuration for all environments: - Service definitions (web, daphne, huey, redis, nginx, certbot) - Base ports, networks, dependencies - Health checks - No environment-specific settings

Development Overrides (docker-compose.dev.yml)

Extends base with development-specific settings: - Volume mounts (- .:/app) for code hot-reloading - DATABASE_HOST=host.docker.internal (connects to host MySQL on port 3307) - REDIS_HOST=redis (uses Docker Redis container) - DEBUG=True for daphne and huey - restart: unless-stopped (don't auto-restart during development) - gunicorn --reload flag

Production Overrides (docker-compose.prod.yml)

Extends base with production-specific settings: - NO volume mounts (code baked into image) - DATABASE_HOST=${DATABASE_HOST} (uses DigitalOcean MySQL from .env) - REDIS_HOST=redis (uses Docker Redis container) - DEBUG=False for all services - restart: always (auto-restart on failure) - gunicorn production settings

Usage

Local Development

# Manually specify both files
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

# Or use deploy.sh (auto-detects environment)
./deploy.sh docker-up

Production

# Manually specify both files
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# Or use deploy.sh (auto-detects environment)
./deploy.sh deploy-full

Environment Detection

The deploy.sh script automatically detects your environment:

# Checks for:
1. /srv/uplink/app/.production file
2. hostname = "uplink"

# If either exists → production (uses docker-compose.prod.yml)
# Otherwise → development (uses docker-compose.dev.yml)

Key Differences

Aspect Development Production
Compose Files base + dev base + prod
Code Reloading Yes (volume mounted) No (baked into image)
Database Host MySQL (port 3307) DigitalOcean MySQL
DEBUG Mixed (False for web, True for daphne/huey) False (all services)
Restart Policy unless-stopped always
Gunicorn --reload flag Production optimized
Direct Access localhost:8001 (web), localhost:9000 (daphne) nginx proxy (80/443)

Benefits

No .env changes needed - Same .env works for both pipenv and Docker ✅ Clear separation - Dev and prod settings don't interfere ✅ Shared base - Common config in one place (DRY principle) ✅ Automatic detection - deploy.sh uses right files for environment ✅ Standard practice - Follows Docker Compose best practices

Transitioning from Old Setup

Old way: Single docker-compose.yml with environment variables toggling behavior

New way: - Base config + environment-specific overrides - Clear separation of concerns - Auto-detection of environment

Compatibility: - Can still run pipenv locally (pipenv run honcho start) - Can run Docker locally (./deploy.sh docker-up) - Both use same database (your local MySQL) - Both work simultaneously (different ports)

Common Commands

# Development
./deploy.sh docker-up        # Start dev containers
./deploy.sh docker-down      # Stop dev containers
./deploy.sh docker-restart   # Restart dev containers
./deploy.sh docker-logs      # View dev logs

# Production (on production server)
./deploy.sh deploy-full      # Full deployment (recommended)
./deploy.sh deploy-quick     # Quick code-only deployment
./deploy.sh deploy-rebuild   # Complete rebuild
./deploy.sh status           # Check status
./deploy.sh logs             # View logs

Migration Notes

For Existing Production Server

  1. Create production marker file:

    touch /srv/uplink/app/.production
    

  2. Deploy script will automatically use production compose files

  3. No other changes needed!

For Local Development

  1. No changes needed - works automatically

  2. deploy.sh detects you're NOT on production server

  3. Uses dev compose files automatically

Troubleshooting

Issue: "Service 'web' is not running"

# Check which files are being used
docker compose -f docker-compose.yml -f docker-compose.dev.yml ps

# Or check environment detection
./deploy.sh status

Issue: "Database connection failed"

# Development: Check host MySQL is running
sudo service mysql status

# Production: Check .env has correct DigitalOcean credentials
grep DATABASE_HOST .env

Issue: "Code changes not reflecting"

# Development: Volume should be mounted
docker compose -f docker-compose.yml -f docker-compose.dev.yml exec web ls -la /app

# Production: Code baked into image, need to rebuild
./deploy.sh deploy-full

Additional Resources