<@ULVA73B9P> im getting this error with this docke...
# ask-marvin
s
@Marvin im getting this error with this docker compose on public domain ui access : Can't connect to Server API at 192.168.29.151/api. Check that it's accessible from your machine. services: postgres: image: postgres:15 container_name: prefect-postgres restart: unless-stopped environment: POSTGRES_USER: prefect POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: prefect volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: pg_isready -h localhost -U $$POSTGRES_USER interval: 2s timeout: 5s retries: 15 ports: - "127.0.0.154325432" # bind to localhost only; open to other VMs later when you move DB off-box redis: image: redis:7 container_name: prefect-redis restart: unless-stopped volumes: - redis_data:/data # Runs migrations once, then exits. API/services containers start only after this succeeds. migrate: image: prefecthq/prefect:3-latest container_name: prefect-migrate depends_on: postgres: condition: service_healthy command: prefect server database upgrade -y environment: PREFECT_SERVER_DATABASE_CONNECTION_URL: postgresql+asyncpg://prefect:${POSTGRES_PASSWORD}@postgres:5432/prefect prefect-api: image: prefecthq/prefect:3-latest container_name: prefect-api restart: unless-stopped depends_on: migrate: condition: service_completed_successfully postgres: condition: service_healthy redis: condition: service_started # --no-services: this instance only serves API/UI traffic; scheduling # and automations run on the separate prefect-services container below. command: prefect server start --host 0.0.0.0 --port 4200 --no-services --keep-alive-timeout 60 environment: PREFECT_HOME: /home/prefect/.prefect PREFECT_SERVER_LOGGING_LEVEL: INFO PREFECT_SERVER_API_AUTH_STRING: ${PREFECT_SERVER_API_AUTH_STRING} # Tells the browser-side UI where to reach the API. Must be an address # your browser (not the container) can resolve — the VM's real IP, # not 127.0.0.1 or a container name. PREFECT_SERVER_UI_API_URL: http://${PREFECT_VM_IP}:4200/api PREFECT_SERVER_DATABASE_CONNECTION_URL: postgresql+asyncpg://prefect:${POSTGRES_PASSWORD}@postgres:5432/prefect PREFECT_SERVER_DATABASE_MIGRATE_ON_START: "false" PREFECT_SERVER_EVENTS_MESSAGING_BROKER: prefect_redis.messaging PREFECT_SERVER_EVENTS_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" # Separate Redis DB (1) from app-level use (0), matching Prefect's docs example PREFECT_SERVER_DOCKET_URL: redis://redis:6379/1 volumes: - prefect_home:/home/prefect/.prefect expose: - "4200" prefect-services: image: prefecthq/prefect:3-latest container_name: prefect-services restart: unless-stopped depends_on: migrate: condition: service_completed_successfully postgres: condition: service_healthy redis: condition: service_started command: prefect server services start environment: PREFECT_HOME: /home/prefect/.prefect PREFECT_SERVER_LOGGING_LEVEL: INFO PREFECT_SERVER_DATABASE_CONNECTION_URL: postgresql+asyncpg://prefect:${POSTGRES_PASSWORD}@postgres:5432/prefect PREFECT_SERVER_DATABASE_MIGRATE_ON_START: "false" PREFECT_SERVER_EVENTS_MESSAGING_BROKER: prefect_redis.messaging PREFECT_SERVER_EVENTS_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" PREFECT_SERVER_DOCKET_URL: redis://redis:6379/1 nginx: image: nginx:1.27-alpine container_name: prefect-nginx restart: unless-stopped depends_on: - prefect-api ports: - "4200:4200" # this is what workers / UI / API clients hit volumes: - ./nginx.conf/etc/nginx/conf.d/default.confro volumes: postgres_data: redis_data: prefect_home:
m
thought for 294.0 seconds
A few things stand out immediately. Most likely root cause: your UI is being told to call an API URL that the browser cannot actually reach, or Prefect is failing to start correctly because some env vars are malformed. I also see a definite config problem in your compose:
Copy code
yaml
PREFECT_SERVER_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect>:${POSTGRES_PASSWORD}@postgres:5432/prefect
...
PREFECT_SERVER_DOCKET_URL: <redis://redis:6379/1>
Those
< >
are literal characters in Docker Compose, not placeholders. That makes both URLs invalid. Also, your error mentions:
Can't connect to Server API at <http://192.168.29.151:4200/api>
So the browser is trying to call that exact URL. If you're accessing Prefect through a public domain, then
PREFECT_SERVER_UI_API_URL
should usually be your public domain, not the private VM IP. What to fix 1. Remove the angle brackets from the DB and Redis URLs 2. Set
PREFECT_SERVER_UI_API_URL
to the exact public URL users open in the browser 3. Make sure nginx proxies both
/
and
/api
4. Verify
/ui-settings
and
/api/health
Here’s the corrected compose snippet:
Copy code
yaml
services:
  prefect-api:
    image: prefecthq/prefect:3-latest
    container_name: prefect-api
    restart: unless-stopped
    depends_on:
      migrate:
        condition: service_completed_successfully
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    command: prefect server start --host 0.0.0.0 --port 4200 --no-services --keep-alive-timeout 60
    environment:
      PREFECT_HOME: /home/prefect/.prefect
      PREFECT_SERVER_LOGGING_LEVEL: INFO
      PREFECT_SERVER_API_AUTH_STRING: ${PREFECT_SERVER_API_AUTH_STRING}

      # Use your PUBLIC URL here if accessing through a domain
      PREFECT_SERVER_UI_API_URL: <https://your-domain.com/api>

      PREFECT_SERVER_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:${POSTGRES_PASSWORD}@postgres:5432/prefect>
      PREFECT_SERVER_DATABASE_MIGRATE_ON_START: "false"

      PREFECT_SERVER_EVENTS_MESSAGING_BROKER: prefect_redis.messaging
      PREFECT_SERVER_EVENTS_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"
      PREFECT_SERVER_DOCKET_URL: <redis://redis:6379/1>
    volumes:
      - prefect_home:/home/prefect/.prefect
    expose:
      - "4200"

  prefect-services:
    image: prefecthq/prefect:3-latest
    container_name: prefect-services
    restart: unless-stopped
    depends_on:
      migrate:
        condition: service_completed_successfully
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    command: prefect server services start
    environment:
      PREFECT_HOME: /home/prefect/.prefect
      PREFECT_SERVER_LOGGING_LEVEL: INFO
      PREFECT_SERVER_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:${POSTGRES_PASSWORD}@postgres:5432/prefect>
      PREFECT_SERVER_DATABASE_MIGRATE_ON_START: "false"
      PREFECT_SERVER_EVENTS_MESSAGING_BROKER: prefect_redis.messaging
      PREFECT_SERVER_EVENTS_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"
      PREFECT_SERVER_DOCKET_URL: <redis://redis:6379/1>
A working nginx config should look roughly like: ```nginx server { listen 4200; server_name _; location / { proxy_pass http://prefect-api:4200; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } }
Copy code
*Important note about auth:*  
If you set `PREFECT_SERVER_API_AUTH_STRING`, the browser/UI must be able to authenticate too. If nginx is not injecting the required auth header, the UI can fail to talk to the API. If this is just an initial setup, try temporarily removing:

```yaml
PREFECT_SERVER_API_AUTH_STRING
and test again. If it works without auth, then the next issue is proxying auth correctly. Quick checks Run these from your machine/browser against the public URL: 1. UI settings
Copy code
bash
curl <https://your-domain.com/ui-settings>
You should see something like:
Copy code
json
{"api_url":"<https://your-domain.com/api>"}
2. API health
Copy code
bash
curl <https://your-domain.com/api/health>
3. Container logs
Copy code
bash
docker compose logs prefect-api
docker compose logs nginx
docker compose logs migrate
If
prefect-api
is failing to boot because of the bad DB/Redis URLs, it should show there. Docs - Self-host Prefect - Reverse proxy / UI hosting - Docker Compose guide If you want, send your
nginx.conf
too — that’s probably the other half of the problem.