<@ULVA73B9P> I’ve setup my homeserver with prefect...
# ask-marvin
n
@Marvin I’ve setup my homeserver with prefect via docker compose, but I can’t seem to connect to the dashboard on my dev device
m
thought for 109.8 seconds
Got it — let’s get your dashboard reachable from your dev device. A few common gotchas with Docker Compose on a home server: Quick checklist - Use the server’s IP and port 4200 from your dev device: http://YOUR_SERVER_IP:4200/ - Make sure the Prefect server is listening on all interfaces (0.0.0.0), not just localhost - Ensure port 4200 is published in Docker and not blocked by a firewall Minimal working compose service Add this to your compose (or compare with yours). The key bits are the port mapping and
--host 0.0.0.0
or
PREFECT_SERVER_API_HOST=0.0.0.0
.
Copy code
services:
  prefect-server:
    image: prefecthq/prefect:3-latest
    command: prefect server start --host 0.0.0.0 --port 4200 --no-services
    environment:
      # Ensures the API binds to all interfaces for LAN access
      PREFECT_SERVER_API_HOST: 0.0.0.0
    ports:
      - "4200:4200"
    restart: unless-stopped
Note: In Prefect 3.x, the UI and API are served on the same port (default 4200). The dashboard is at
/
and the health endpoint is
/api/health
. Quick diagnostics - From the Docker host:
Copy code
docker ps
  # confirm "0.0.0.0:4200->4200/tcp" or similar appears for the Prefect container

  docker logs <prefect-server-container> --tail=100

  # If you have curl on the host:
  curl -sS <http://localhost:4200/api/health>
- From your dev device on the same network:
Copy code
curl -sS <http://YOUR_SERVER_IP:4200/api/health>
Expect:
{"status":"healthy"}
If you’re running the full stack (Postgres/Redis/services), a common compose snippet looks like:
Copy code
services:
  postgres:
    image: postgres:14
    environment:
      POSTGRES_USER: prefect
      POSTGRES_PASSWORD: prefect
      POSTGRES_DB: prefect
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7
    volumes:
      - redis_data:/data

  prefect-server:
    image: prefecthq/prefect:3-latest
    depends_on:
      - postgres
      - redis
    environment:
      PREFECT_API_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
      PREFECT_SERVER_API_HOST: 0.0.0.0
      PREFECT_MESSAGING_BROKER: prefect_redis.messaging
      PREFECT_MESSAGING_CACHE: prefect_redis.messaging
      PREFECT_REDIS_MESSAGING_HOST: redis
      PREFECT_REDIS_MESSAGING_PORT: 6379
    command: prefect server start --no-services
    ports:
      - "4200:4200"

  prefect-services:
    image: prefecthq/prefect:3-latest
    depends_on:
      - prefect-server
    environment:
      PREFECT_API_DATABASE_CONNECTION_URL: <postgresql+asyncpg://prefect:prefect@postgres:5432/prefect>
      PREFECT_MESSAGING_BROKER: prefect_redis.messaging
      PREFECT_MESSAGING_CACHE: prefect_redis.messaging
      PREFECT_REDIS_MESSAGING_HOST: redis
      PREFECT_REDIS_MESSAGING_PORT: 6379
    command: prefect server services start

volumes:
  postgres_data:
  redis_data:
Other things to check - Firewalls: Ensure the host allows inbound TCP 4200 from your LAN. - Reverse proxy/TLS: If you’re fronting Prefect with a proxy and using a different hostname/port, you may need to set
PREFECT_SERVER_UI_API_URL
so the UI can reach the API. - Don’t set
PREFECT_API_URL
in the server container; that’s for workers/clients. Docs for reference - Self-hosted via Docker Compose - Server in Docker - Settings reference (see
PREFECT_SERVER_API_HOST
,
PREFECT_SERVER_UI_API_URL
) If you can, please share: - Your
docker-compose.yml
service(s) for Prefect - The URL you’re trying from your dev device - Output of:
Copy code
docker ps
  docker logs <prefect-server-container> --tail=100
  curl -sS <http://YOUR_SERVER_IP:4200/api/health>  # from the dev device
I’ll pinpoint what’s blocking access.
n
@Marvin using curl returned true and not what you mentioned
m
thought for 110.9 seconds
Thanks for the check — that helps. In Prefect 3.x, the health endpoint at /api/health intentionally returns the boolean literal
true
(not JSON). So what you saw is expected. A couple of handy probes: - Liveness: http://YOUR_SERVER_IP:4200/api/health → returns
true
- Readiness (checks DB): http://YOUR_SERVER_IP:4200/api/ready → returns
{"message":"OK"}
on success or 503 with an error if the DB isn’t reachable If curl to /api/health from your dev device works, but you still can’t load the dashboard in a browser, likely culprits are: - The UI/API isn’t bound externally: ensure your compose sets
PREFECT_SERVER_API_HOST=0.0.0.0
or
--host 0.0.0.0
, and that you’ve published
4200:4200
. - Browser reaching a different host/port than you’re curling (e.g., proxy or HTTPS mismatch). - Firewall blocking port 4200. If you can share: - The Prefect service section of your docker-compose.yml - The exact URL you’re hitting in the browser - Output of:
Copy code
docker ps
  docker logs <prefect-server-container> --tail=100
  curl -sS <http://YOUR_SERVER_IP:4200/api/ready>
I’ll pinpoint the next step.
n
@Marvin I did indeed get an ok ready, and http://my_ip:4200/api is what ive been using
m
thought for 72.9 seconds
Great — if /api/ready returns OK, your server and DB are healthy. The dashboard isn’t at /api though. That path is just the API. Open the UI at the root: - http://my_ip:4200/ If the root doesn’t load or shows “cannot reach API”: - Ensure the UI is enabled (it’s on by default). Don’t start with
--no-ui
, and make sure
PREFECT_UI_ENABLED=true
(or
PREFECT_SERVER_UI_ENABLED=true
) isn’t overridden to false. - If you’re using a proxy or a different hostname/port, set:
Copy code
PREFECT_SERVER_UI_API_URL=<http://my_ip:4200/api>
This gives the UI an explicit API endpoint your browser can reach. Quick compose snippet (key bits):
Copy code
services:
  prefect-server:
    image: prefecthq/prefect:3-latest
    command: prefect server start --host 0.0.0.0 --port 4200 --no-services
    environment:
      PREFECT_SERVER_API_HOST: 0.0.0.0
      # Optional but helpful if proxying/alternate hostnames:
      # PREFECT_SERVER_UI_API_URL: <http://my_ip:4200/api>
    ports:
      - "4200:4200"
Docs for reference: - Server in Docker - Settings reference (see
PREFECT_UI_ENABLED
,
PREFECT_SERVER_UI_API_URL
) Can you try http://my_ip:4200/ directly and let me know what you see? If it’s still not loading, please share any console/network errors from the browser or the last 100 lines of the Prefect server logs:
Copy code
docker logs <prefect-server-container> --tail=100
n
@Marvin Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at
m
thought for 134.8 seconds
Got it — your browser’s blocking the UI calls to the API due to CORS. Let’s fix it. Why it’s happening - You’re opening the UI at one origin (e.g., http://my_ip:4200/), and the UI is trying to call an API origin the browser considers different. - Or your reverse proxy/hostname doesn’t match where the API actually is. Quick fix (most cases) - Explicitly tell the UI which API URL to use and ensure CORS allows your UI origin. In your Prefect server service, set:
Copy code
environment:
  # UI -> API URL your browser can reach
  PREFECT_SERVER_UI_API_URL: <http://my_ip:4200/api>

  # CORS: allow your UI origin(s)
  PREFECT_SERVER_API_CORS_ALLOWED_ORIGINS: "<http://my_ip:4200>"
  PREFECT_SERVER_API_CORS_ALLOWED_METHODS: "*"
  PREFECT_SERVER_API_CORS_ALLOWED_HEADERS: "*"
Then restart the container. Notes - Origins must match exactly: scheme, host, and port. For example, http://my_ip:4200 is different from http://localhost:4200 or https://my_ip:4200. - If you’re using a proxy/hostname, change both values to match it, e.g.:
Copy code
PREFECT_SERVER_UI_API_URL: <https://prefect.example.com/api>
  PREFECT_SERVER_API_CORS_ALLOWED_ORIGINS: "<https://prefect.example.com>"
- Defaults are permissive (*), but some proxies strip headers or the UI may infer an API URL that’s cross-origin. Setting
PREFECT_SERVER_UI_API_URL
removes ambiguity. Sanity checks - After setting these, open your browser’s DevTools -> Network: - Requests to /api/* should now include Access-Control-Allow-Origin in responses. - Preflight OPTIONS requests should return 200 with the CORS headers. - Verify endpoints directly from the browser: - http://my_ip:4200/api/health → true - http://my_ip:4200/api/ready → {"message":"OK"} If you still see CORS errors, please share: - The exact URL in your browser’s address bar - The Request URL and Response Headers for a failed Network request - Your Prefect service’s environment section from docker-compose.yml I’ll tailor the exact values you need.