Shubham
08/09/2026, 9:12 AMMarvin
08/09/2026, 9:12 AMMarvin
08/09/2026, 9:17 AMyaml
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:
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;Marvin
08/09/2026, 9:17 AM*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
bash
curl <https://your-domain.com/ui-settings>
You should see something like:
json
{"api_url":"<https://your-domain.com/api>"}
2. API health
bash
curl <https://your-domain.com/api/health>
3. Container logs
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.