The production-local environment allows you to run production builds locally for verification and debugging. This uses the same production Dockerfiles and configuration as the production environment, but with localhost URLs for local access.
- Verify production builds work correctly before deployment
- Debug production issues in a local environment
- Test production configurations without affecting production
Copy the example file and customize as needed:
cp .env.example .env.prod-localThe .env.example file contains a comprehensive template with all available environment variables. At minimum, you need to set the URL configuration for localhost access:
# Backend URL - use localhost for local access
BACKEND_URL=http://localhost:8000
# Payload CMS URLs - use localhost for local access
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3001
FRONTEND_URL=http://localhost:3000
# Frontend public URLs - use localhost for local access
NEXT_PUBLIC_BACKEND_URL=http://localhost:8000
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3001
# CORS Origins - include localhost for local access
CORS_ORIGINS=http://localhost:3000,http://localhost:3001Note: The .env.prod-local file is gitignored and should not be committed. Each developer should create their own copy from .env.example.
Make sure you have the necessary environment variables set in your service-specific .env files:
backend/.env- Backend configuration (GOOGLE_API_KEY, MONGO_URI, etc.)payload_cms/.env- Payload CMS configuration (DATABASE_URI, PAYLOAD_SECRET, etc.)
./scripts/run-prod-local.shThis script will:
- Check if
.env.prod-localexists - Check for existing containers that might conflict (and warn you)
- Load environment variables from
.env.prod-local - Run
docker-compose.prod-local.ymlwith production builds
Note: If you have existing containers from previous runs, the script will prompt you. You can stop them first with:
docker-compose -f docker-compose.prod-local.yml down
docker-compose -f docker-compose.dev.yml down# Export variables from .env.prod-local
export $(cat .env.prod-local | xargs)
# Run docker-compose with production-local file
docker-compose -f docker-compose.prod-local.yml up --buildexport $(cat .env.prod-local | xargs) && docker-compose -f docker-compose.prod-local.yml up --buildThe production-local environment includes the full production stack:
- MongoDB - Database (port 27017)
- Backend - FastAPI backend (port 8000)
- Payload CMS - Content management (port 3001)
- Frontend - Next.js frontend (port 3000)
- Prometheus - Metrics collection (port 9090)
- Grafana - Metrics visualization (port 3002)
- Cloudflared - Tunnel (optional, disabled if CLOUDFLARE_TUNNEL_TOKEN not set)
Once started, you can access:
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
- Backend API Docs: http://localhost:8000/docs
- Payload CMS Admin: http://localhost:3001/admin
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3002 (requires GRAFANA_ADMIN_PASSWORD env var)
| Aspect | Development | Production-Local | Production |
|---|---|---|---|
| Dockerfiles | Dockerfile.dev |
Dockerfile (prod) |
Dockerfile (prod) |
| Hot Reload | ✅ Yes | ❌ No | ❌ No |
| Code Mounts | ✅ Yes | ❌ No | ❌ No |
| Build Optimization | ❌ No | ✅ Yes | ✅ Yes |
| Monitoring | ❌ No | ✅ Yes | ✅ Yes |
| URLs | localhost | localhost | Production domains |
| NODE_ENV | development | production | production |
| Container Names | -dev suffix |
-prod-local suffix |
No suffix |
| Aspect | Production-Local | Production |
|---|---|---|
| URLs | localhost | Production domains |
| Cloudflared | Optional | Required |
| Container Names | -prod-local suffix |
No suffix |
| Volumes | Separate | Separate |
If you get an error like "The container name is already in use", stop existing containers first:
# Stop any running docker-compose environments
docker-compose -f docker-compose.prod-local.yml down
docker-compose -f docker-compose.dev.yml down
# Or stop all litecoin containers
docker ps -a --filter "name=litecoin-" --format "{{.Names}}" | xargs -r docker stop
docker ps -a --filter "name=litecoin-" --format "{{.Names}}" | xargs -r docker rmThe run-prod-local.sh script will now warn you about existing containers and ask for confirmation before proceeding.
If you get port conflicts, make sure:
- Development environment is stopped:
docker-compose -f docker-compose.dev.yml down - Production-local environment is stopped:
docker-compose -f docker-compose.prod-local.yml down - No other services are using ports 3000, 3001, 8000, 9090, 3002, 27017
- Ensure
.env.prod-localexists in the project root - Check that
.env.prod-localhas no syntax errors - Verify variables are exported:
env | grep BACKEND_URL
- Ensure all required environment variables are set in service
.envfiles - Check Docker build logs:
docker-compose -f docker-compose.prod-local.yml build --no-cache - Verify Dockerfile syntax and dependencies
- Check service logs:
docker-compose -f docker-compose.prod-local.yml logs <service-name> - Verify health checks:
docker ps(check STATUS column) - Ensure MongoDB is healthy before other services start
The production-local environment uses the same Docker Compose configuration as production, which currently runs MongoDB and Redis without authentication. This is acceptable for local testing but must be enabled before public launch (see RED_TEAM_ASSESSMENT_COMBINED.md - CRIT-3, CRIT-4).
When authentication is enabled:
- Update
MONGO_URIandDATABASE_URIto include credentials - Update
REDIS_URLto include password - Test authentication flow in production-local before deploying
Status: Code already written, needs to be enabled (~1-2 hours). See security assessment for details.
- Always test in production-local before deploying to production
- Use production-local for debugging production-like issues
- Keep
.env.prod-localupdated with any new environment variables - Clean up after testing:
docker-compose -f docker-compose.prod-local.yml down -v - Don't commit
.env.prod-local- it's gitignored for a reason - Enable MongoDB/Redis authentication before public deployment
To stop and remove all production-local containers and volumes:
docker-compose -f docker-compose.prod-local.yml down -vTo stop but keep volumes (faster for next run):
docker-compose -f docker-compose.prod-local.yml down