pradana adnyana
12/24/2025, 5:42 AMMarvin
12/24/2025, 5:42 AMMarvin
12/24/2025, 5:46 AMdeploy.replicas: 3 section is ignored by docker compose unless you’re using Docker Swarm. You end up with a single prefect-api instance.
- The ports line - "4200-4202:4200" is invalid for compose (a host range can’t map to a single container port). In practice, this means nothing ends up published on 4200.
- Bonus: your database URL strings have angle brackets. Those are placeholders in docs; keep the value without < > or the DB connection/migration will fail and the API won’t start.
How to fix:
1) Publish a single API instance on 4200
prefect-api:
image: prefecthq/prefect:3-latest
depends_on:
migrate:
condition: service_completed_successfully
postgres:
condition: service_healthy
redis:
condition: service_started
command: prefect server start --host 0.0.0.0 --no-services
environment:
PREFECT_API_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
PREFECT_API_DATABASE_MIGRATE_ON_START: "false"
PREFECT_MESSAGING_BROKER: prefect_redis.messaging
PREFECT_MESSAGING_CACHE: prefect_redis.messaging
PREFECT_SERVER_EVENTS_CAUSAL_ORDERING: prefect_redis.ordering
PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE: prefect_redis.lease_storage
PREFECT_REDIS_MESSAGING_HOST: redis
PREFECT_REDIS_MESSAGING_PORT: "6379"
ports:
- "4200:4200"
Also update the same DB URL (no angle brackets) in the migrate and prefect-background services.
2) Verify it’s up
- From your host: curl <http://127.0.0.1:4200/api/health>
- Or check logs: docker compose logs -f prefect-api
If you truly want multiple API replicas locally:
- Don’t use the deploy: section with compose; instead use docker compose up --scale prefect-api=3.
- You cannot publish the same host port from multiple replicas. Put the API behind a reverse proxy/load balancer (e.g., Traefik/Nginx) or run a single API for local dev.
Notes:
- --host 0.0.0.0 is correct for binding inside the container.
- Your Redis/messaging env vars are valid for Prefect 3.
- Default server host/port are 127.0.0.1:4200; binding to 0.0.0.0 and publishing 4200 exposes it to your host.
References:
- Self-hosted scaling guide: Prefect self-hosted scaling
- CLI server commands: prefect server CLIpradana adnyana
12/24/2025, 5:47 AMMarvin
12/24/2025, 5:47 AMMarvin
12/24/2025, 5:49 AMFROM prefecthq/prefect:3-latest
RUN pip install --no-cache-dir "prefect-redis>=0.5"
docker-compose.yml
```
services:
traefik:
image: traefik:v3.1
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
# Uncomment TLS if you want automatic certs with Let's Encrypt
# - --entrypoints.websecure.address=:443
# - --certificatesresolvers.le.acme.tlschallenge=true
# - --certificatesresolvers.le.acme.email=${ACME_EMAIL}
# - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
# - "443:443"
volumes:
- /var/run/docker.sock/var/run/docker.sockro
# - letsencrypt:/letsencrypt
restart: unless-stopped
postgres:
image: postgres:15
environment:
POSTGRES_USER: ${POSTGRES_USER:-prefect}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: ${POSTGRES_DB:-prefect}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -U $$POSTGRES_USER"]
interval: 5s
timeout: 5s
retries: 20
restart: unless-stopped
redis:
image: redis:7
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 20
restart: unless-stopped
migrate:
build: .
depends_on:
postgres:
condition: service_healthy
environment:
PREFECT_API_DATABASE_CONNECTION_URL: postgresql+asyncpg://${POSTGRES_USER prefect}${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-prefect}
command: prefect server database upgrade -y
restart: "no"
prefect-api:
build: .
depends_on:
migrate:
condition: service_completed_successfully
postgres:
condition: service_healthy
redis:
condition: service_started
environment:
PREFECT_API_DATABASE_CONNECTION_URL: postgresql+asyncpg://${POSTGRES_USER prefect}${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-prefect}
PREFECT_API_DATABASE_MIGRATE_ON_START: "false"
# Redis-backed messaging for scaled deployments
PREFECT_MESSAGING_BROKER: prefect_redis.messaging
PREFECT_MESSAGING_CACHE: prefect_redis.messaging
PREFECT_SERVER_EVENTS_CAUSAL_ORDERING: prefect_redis.ordering
PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE: prefect_redis.lease_storage
PREFECT_REDIS_MESSAGING_HOST: redis
PREFECT_REDIS_MESSAGING_PORT: "6379"
# Optional auth if your Redis requires it
# PREFECT_REDIS_MESSAGING_USERNAME: default
# PREFECT_REDIS_MESSAGING_PASSWORD: yourpassword
command: prefect server start --host 0.0.0.0 --no-services
labels:
- traefik.enable=true
- traefik.http.routers.prefect.rule=Host(${PREFECT_HOST})
- traefik.http.routers.prefect.entrypoints=web
# For TLS via websecure:
# - traefik.http.routers.prefect.tls=true
# - traefik.http.routers.prefect.tls.certresolver=le
- traefik.http.services.prefect.loadbalancer.server.port=4200
restart: unless-stopped
prefect-background:
build: .
depends_on:
migrate:
condition: service_completed_successfully
postgres:
condition: service_healthy
redis:
condition: service_started
environment:Marvin
12/24/2025, 5:49 AM.env example
# Domain that Traefik should route to your Prefect API/UI
PREFECT_HOST=prefect.example.com
# DB credentials (use stronger passwords and consider Docker secrets)
POSTGRES_USER=prefect
POSTGRES_PASSWORD=change-me
POSTGRES_DB=prefect
# For TLS with Traefik (if you uncomment TLS flags)
# ACME_EMAIL=you@example.com
How to run
- Build the image (includes prefect-redis):
docker compose build
- Start the stack:
docker compose up -d
- Scale API replicas (Traefik will load-balance them):
docker compose up -d --scale prefect-api=3
```
- Verify health:
- API: http://your-domain/api/health (or http://localhost if you point DNS to it)
- Logs: docker compose logs -f prefect-api and docker compose logs -f prefect-background
Notes
- For a single-node/no-LB setup, you can remove Traefik and expose the API directly with ports: ["4200:4200"] on prefect-api (then don’t scale).
- For production, consider managed Postgres/Redis and externalize their backups and monitoring.
- The Redis-backed settings are required for multi-replica API deployments and robust event/concurrency handling in Prefect 3.
Docs
- Self-hosted scaling: Prefect self-hosted scaling
- Server CLI: prefect server CLIBring your towel and join one of the fastest growing data communities. Welcome to our second-generation open source orchestration platform, a completely rethought approach to dataflow automation.
Powered by