docker-compose.dev.yml
Rama main · réplica de lectura del repositorio original.
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_USER: freeframe
POSTGRES_PASSWORD: freeframe
POSTGRES_DB: freeframe
ports:
- "5433:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U freeframe"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redisdata:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
# S3 storage. Silo is a maintained fork of MinIO: the minio/minio and minio/mc
# images can no longer be pulled from Docker Hub (#461). It reads the same
# MINIO_* variables and opens an existing miniodata volume as is, so the
# service keeps its name and S3_ENDPOINT stays http://minio:9000.
# Browser CORS is not set here: the API writes the bucket's CORS rules at
# startup from FRONTEND_URL and CORS_ALLOW_ORIGINS.
minio:
image: pgsty/silo:RELEASE.2026-09-16T00-00-00Z
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
ports:
- "9000:9000"
- "9001:9001"
volumes:
- miniodata:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 5s
timeout: 5s
retries: 5
minio-init:
image: pgsty/mc:RELEASE.2026-09-16T00-00-00Z
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set local http://minio:9000 minioadmin minioadmin;
mc mb --ignore-existing local/freeframe;
mc anonymous set download local/freeframe;
exit 0;
"
api:
build:
context: .
dockerfile: apps/api/Dockerfile
ports:
- "8000:8000"
env_file:
- .env
environment:
DATABASE_URL: postgresql://freeframe:freeframe@postgres:5432/freeframe
REDIS_URL: redis://redis:6379/0
# Storage: "minio" for local MinIO (dev), "s3" for AWS S3 (prod)
S3_STORAGE: ${S3_STORAGE:-minio}
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin}
S3_ENDPOINT: http://minio:9000
S3_BUCKET: ${S3_BUCKET:-freeframe}
S3_REGION: ${S3_REGION:-us-east-1}
S3_PUBLIC_ENDPOINT: ${S3_PUBLIC_ENDPOINT:-http://localhost:9000}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio:
condition: service_healthy
volumes:
- ./apps/api:/workspace/apps/api
- ./packages/transcoder:/workspace/packages/transcoder
command: >
sh -c "cd /workspace/apps/api && alembic upgrade head && cd /workspace && uvicorn apps.api.main:app --host 0.0.0.0 --port 8000 --reload"
worker:
build:
context: .
dockerfile: apps/api/Dockerfile
env_file:
- .env
environment:
DATABASE_URL: postgresql://freeframe:freeframe@postgres:5432/freeframe
REDIS_URL: redis://redis:6379/0
S3_STORAGE: ${S3_STORAGE:-minio}
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin}
S3_ENDPOINT: http://minio:9000
S3_BUCKET: ${S3_BUCKET:-freeframe}
S3_REGION: ${S3_REGION:-us-east-1}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio:
condition: service_healthy
volumes:
- ./apps/api:/workspace/apps/api
- ./packages/transcoder:/workspace/packages/transcoder
command: celery -A apps.api.tasks.celery_app worker -Q transcoding -c ${TRANSCODING_CONCURRENCY:-2} --loglevel=info
email_worker:
build:
context: .
dockerfile: apps/api/Dockerfile
env_file:
- .env
environment:
DATABASE_URL: postgresql://freeframe:freeframe@postgres:5432/freeframe
REDIS_URL: redis://redis:6379/0
S3_STORAGE: ${S3_STORAGE:-minio}
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin}
S3_ENDPOINT: http://minio:9000
S3_BUCKET: ${S3_BUCKET:-freeframe}
S3_REGION: ${S3_REGION:-us-east-1}
depends_on:
redis:
condition: service_healthy
volumes:
- ./apps/api:/workspace/apps/api
- ./packages/transcoder:/workspace/packages/transcoder
command: celery -A apps.api.tasks.celery_app worker -Q email_high,email_low -c ${EMAIL_CONCURRENCY:-2} --loglevel=info
# Housekeeping worker. Present in dev as well as prod so the periodic tasks
# are exercised locally: #240 was invisible for months precisely because dev
# ran neither this worker nor beat.
#
# NOTE: this means your local stack really does delete things on a schedule.
# Within the hour, reap_stale_uploads soft-deletes AssetVersions stuck in
# uploading/failed past STALE_UPLOAD_TIMEOUT_HOURS and drops their S3 objects
# (a failed version whose original is still in storage is kept);
# at 03:00 UTC, cleanup_soft_deleted hard-deletes anything soft-deleted past
# SOFT_DELETE_RETENTION_DAYS, cascade and S3 reclaim included. Both take `0`
# in your .env to switch them off if you keep long-lived local data.
maintenance_worker:
build:
context: .
dockerfile: apps/api/Dockerfile
env_file:
- .env
environment:
DATABASE_URL: postgresql://freeframe:freeframe@postgres:5432/freeframe
REDIS_URL: redis://redis:6379/0
S3_STORAGE: ${S3_STORAGE:-minio}
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin}
S3_ENDPOINT: http://minio:9000
S3_BUCKET: ${S3_BUCKET:-freeframe}
S3_REGION: ${S3_REGION:-us-east-1}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio:
condition: service_healthy
volumes:
- ./apps/api:/workspace/apps/api
- ./packages/transcoder:/workspace/packages/transcoder
command: celery -A apps.api.tasks.celery_app worker -Q maintenance -c ${MAINTENANCE_CONCURRENCY:-1} --loglevel=info
beat:
build:
context: .
dockerfile: apps/api/Dockerfile
env_file:
- .env
environment:
DATABASE_URL: postgresql://freeframe:freeframe@postgres:5432/freeframe
REDIS_URL: redis://redis:6379/0
S3_STORAGE: ${S3_STORAGE:-minio}
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin}
S3_ENDPOINT: http://minio:9000
S3_BUCKET: ${S3_BUCKET:-freeframe}
S3_REGION: ${S3_REGION:-us-east-1}
depends_on:
redis:
condition: service_healthy
volumes:
- ./apps/api:/workspace/apps/api
- ./packages/transcoder:/workspace/packages/transcoder
command: celery -A apps.api.tasks.celery_app beat --loglevel=info -s /tmp/celerybeat-schedule
web:
image: node:20-alpine
working_dir: /app
ports:
- "3000:3000"
environment:
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://localhost:8000}
# Sub-path deployments: empty serves the app from the domain root.
- NEXT_PUBLIC_BASE_PATH=${NEXT_PUBLIC_BASE_PATH:-}
# Server-to-server, for the branding Next renders into the first byte.
# NEXT_PUBLIC_API_URL is written for the browser, and inside this
# container `localhost:8000` is this container, not the API.
- API_INTERNAL_URL=${API_INTERNAL_URL:-http://api:8000}
- NODE_ENV=development
- HOSTNAME=0.0.0.0
volumes:
- ./apps/web:/app
- web_node_modules:/app/node_modules
command: sh -c "npm install && npx next dev --hostname 0.0.0.0"
depends_on:
- api
healthcheck:
# See docker-compose.prod.yml: `/` is a 404 when a base path is set.
test:
[
"CMD-SHELL",
"wget -q --spider \"http://localhost:3000${NEXT_PUBLIC_BASE_PATH:-}/login\"",
]
interval: 30s
timeout: 10s
retries: 10
start_period: 60s
volumes:
pgdata:
miniodata:
redisdata:
web_node_modules: