Skip to content

Docker Workflow Guide

This guide explains our Docker workflow for local development and how production deployments work.

Overview

  • Local Development: docker-compose.local.yml with Supabase CLI
  • Production: Individual containers managed by deploy-unraid.yml GitHub Actions workflow

Local Development Workflow

Prerequisites

  • Docker Desktop installed and running
  • Supabase CLI installed (brew install supabase/tap/supabase)
  • Git

Quick Start

# 1. Clone and navigate to the project
git clone https://github.com/eddie-rowe/vertical-farm.git
cd vertical-farm

# 2. Start the local development environment
make up
# or
./scripts/setup-local-dev.sh

This script will: 1. Check prerequisites (Docker, Supabase CLI) 2. Start Supabase services locally 3. Create .env.local with auto-populated Supabase keys 4. Start application containers with hot-reloading

Access Points

  • Frontend: http://localhost:3000
  • Backend API: http://localhost:8000
  • API Docs: http://localhost:8000/docs
  • Supabase Studio: http://localhost:54323

Key Features of Local Setup

  • Hot Reloading: Code changes are reflected immediately
  • Volume Mounts: Your local code is mounted into containers
  • Supabase CLI: Full local Supabase instance (no cloud costs)
  • Optional Datadog: Use --profile monitoring to include Datadog agent

Common Local Commands

# View logs
make logs                    # All services
make logs-service           # Specific service (interactive)

# Stop everything
make down                   # Stops containers and asks about Supabase
make down-docker           # Stops only Docker containers

# Reset database
supabase db reset          # Wipes and re-applies migrations

# Clean up
make clean-docker          # Removes containers and volumes

Production Deployment Workflow

unRAID Deployment via GitHub Actions

Production uses a sophisticated unRAID deployment strategy with individual container management:

  1. Trigger: Merge to main or manual workflow dispatch
  2. Build Phase:
  3. Backend and Frontend images built separately
  4. Images pushed to GitHub Container Registry (GHCR)
  5. Deploy Phase (via self-hosted runner on unRAID):
  6. Pulls new images from GHCR
  7. Stops existing containers
  8. Deploys new containers with docker run
  9. Each service managed individually for zero-downtime updates

How It Works

The deploy-unraid.yml workflow: - Runs on a self-hosted runner directly on your unRAID server - Creates a shared Docker network (vertical-farm-network) - Deploys each container individually: - Backend: Port 8000 - Frontend: Port 3000
- Datadog Agent: Port 8126

Key Benefits

  • unRAID Native: Works perfectly with unRAID's container management UI
  • Zero Downtime: Update services independently
  • Granular Control: Each container configured explicitly
  • Self-Hosted: No external dependencies

Required GitHub Secrets

Configure these in your repository settings:

# Supabase Production
SUPABASE_URL
SUPABASE_ANON_KEY
SUPABASE_SERVICE_KEY
SUPABASE_JWT_SECRET
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY

# Application
NEXT_PUBLIC_API_URL
BACKEND_CORS_ORIGINS
GHCR_TOKEN  # For pulling images

# Datadog
DD_API_KEY
DD_SITE
DD_SERVICE
NEXT_PUBLIC_DD_RUM_APPLICATION_ID
NEXT_PUBLIC_DD_RUM_CLIENT_TOKEN
NEXT_PUBLIC_DD_SITE
NEXT_PUBLIC_DD_SERVICE

# Optional: Database Monitoring
POSTGRES_DATADOG_USERNAME
POSTGRES_DATADOG_PASSWORD
POSTGRES_DATADOG_DBNAME
SUPABASE_METRICS_URL

Manual Container Management

If needed, you can manage containers directly on unRAID:

# View running containers
docker ps

# Update a specific container (example: backend)
docker pull ghcr.io/eddie-rowe/vertical-farm/backend:latest
docker rm -f backend
docker run -d --name backend --network vertical-farm-network \
  -p 8000:8000 \
  -e SUPABASE_URL=... \
  # ... other env vars
  ghcr.io/eddie-rowe/vertical-farm/backend:latest

Environment Variables

Local Development (.env.local)

Created automatically by setup script:

# Supabase Local (auto-populated)
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=<auto-generated>
SUPABASE_SERVICE_KEY=<auto-generated>

# Application
PROJECT_NAME=vertical-farm-local
DEBUG=true
ENVIRONMENT=local

Production Environment

Production environment variables are managed entirely through: - GitHub Secrets: Stored securely in repository settings - GitHub Actions Variables: For non-sensitive configuration - Self-hosted Runner: Accesses secrets during deployment

No .env files are used in production for security reasons.

Key Differences: Local vs Production

Aspect Local Development Production
Deployment Method docker-compose Individual docker run commands
Supabase Local CLI instance Cloud instance
Hot Reload Enabled (volume mounts) Disabled
Debug Mode True False
Container Management Docker Compose unRAID + GitHub Actions
Images Built locally Pulled from GHCR
Datadog Optional (profile) Always enabled
Runner Local machine Self-hosted on unRAID
Network Bridge network vertical-farm-network
Updates Manual restart Zero-downtime via workflow

Troubleshooting

Local Development Issues

Supabase won't start:

# Check status
supabase status

# Reset if needed
supabase stop
supabase start

Port conflicts:

# Check what's using the port
lsof -i :3000  # or :8000, :54321

# Change ports in docker-compose.local.yml if needed

Can't connect to Supabase from container: - Ensure host.docker.internal is used in container environment - Check that Supabase is running: supabase status

Production Issues

Deployment fails: - Check GitHub Actions logs in deploy-unraid.yml workflow - Verify all secrets are set in repository settings - Ensure self-hosted runner is online - Check unRAID server resources

Services unhealthy:

# Check container logs (on unRAID)
docker logs backend --tail=100
docker logs frontend --tail=100
docker logs dd-agent --tail=100

# Restart specific service
docker restart backend

# Manual redeploy
docker rm -f backend
docker run -d --name backend ... # with all env vars

unRAID Specific: - Check unRAID Docker tab for container status - Verify network vertical-farm-network exists - Ensure ports 3000, 8000, 8126 are not conflicting

Best Practices

  1. Never commit .env files - Use .env.example as templates
  2. Test locally first - Always verify changes work with make up
  3. Use health checks - Production containers should define health checks
  4. Monitor deployments - Check Datadog after deployments
  5. Keep images small - Use multi-stage builds in Dockerfiles
  6. Version your deployments - Use git SHA as Docker tags

Migration Guide

If you're updating from the old single docker-compose.yml:

  1. Pull latest changes
  2. Stop existing containers: docker-compose down
  3. Run the new setup: make up
  4. Local development now uses docker-compose.local.yml
  5. Production continues using the unRAID workflow

[[memory:6973530]]