<@ULVA73B9P> Using prefect 2.20. Want to configure...
# marvin-ai
f
@Marvin Using prefect 2.20. Want to configure prefect such that the self hosted UI dashboard can be accessed through my application's URL like as follows: https://my-app.com/prefect-ui using traefik. Is it possible?
m
thought for 151.3 seconds
Yes — in Prefect 2.20, this is possible, but you’ll want to configure it carefully. The key setting is: -
PREFECT_UI_SERVE_BASE=/prefect-ui
And usually also: -
PREFECT_UI_API_URL=<external API URL the browser should call>
For example, if users access Prefect at: - UI:
<https://my-app.com/prefect-ui>
- API:
<https://my-app.com/api>
then set:
Copy code
bash
PREFECT_UI_SERVE_BASE=/prefect-ui
PREFECT_UI_API_URL=<https://my-app.com/api>
What this does -
PREFECT_UI_SERVE_BASE
tells Prefect’s UI to serve under
/prefect-ui
-
PREFECT_UI_API_URL
tells the frontend where to send API requests So yes, serving the self-hosted dashboard behind Traefik at a subpath is supported in 2.20. Important caveat Your reverse proxy needs to be configured consistently with that setup. In practice, you usually either: 1. Preserve the
/prefect-ui
prefix
when forwarding to Prefect, or 2. Strip the prefix only if your upstream routing and app config still line up correctly Because Prefect is explicitly configured with
/prefect-ui
, the safest pattern is to make Traefik route that path to the Prefect server in a way that matches the configured base path. A typical environment example
Copy code
bash
PREFECT_UI_SERVE_BASE=/prefect-ui
PREFECT_UI_API_URL=<https://my-app.com/api>
If your API is also exposed under the same prefix instead, you’d set the API URL accordingly. Things to test after setup -
<https://my-app.com/prefect-ui>
-
<https://my-app.com/prefect-ui/ui-settings>
That
ui-settings
endpoint should return JSON including the API URL the UI will use. One more note Prefect 2.x is in the older generation, and if you later move to Prefect 3.x, deployment/reverse-proxy guidance changes a bit. But for 2.20 specifically, subpath UI hosting is supported. If you want, I can also sketch a Traefik example config for this setup.
f
@Marvin yes create it
m
thought for 21.9 seconds
Absolutely — here’s a Traefik example for exposing Prefect 2.20 at: -
<https://my-app.com/prefect-ui>
I’ll show the cleanest pattern first. Recommended approach Expose the Prefect server behind Traefik and configure Prefect with:
Copy code
bash
PREFECT_UI_SERVE_BASE=/prefect-ui
PREFECT_UI_API_URL=<https://my-app.com/api>
If you want the API under the same subpath family instead, use something like:
Copy code
bash
PREFECT_UI_API_URL=<https://my-app.com/prefect-api>
depending on your routing. --- Option 1: UI at
/prefect-ui
, API at
/api
This is a common setup if your app already owns the main domain. Prefect container env
Copy code
yaml
environment:
  PREFECT_UI_SERVE_BASE: /prefect-ui
  PREFECT_UI_API_URL: <https://my-app.com/api>
Docker Compose + Traefik example
Copy code
yaml
services:
  prefect:
    image: prefecthq/prefect:2.20.0-python3.11
    command: prefect server start --host 0.0.0.0 --port 4200
    environment:
      PREFECT_UI_SERVE_BASE: /prefect-ui
      PREFECT_UI_API_URL: <https://my-app.com/api>
    labels:
      - traefik.enable=true

      # Route UI traffic
      - traefik.http.routers.prefect-ui.rule=Host(`<http://my-app.com|my-app.com>`) && PathPrefix(`/prefect-ui`)
      - traefik.http.routers.prefect-ui.entrypoints=websecure
      - traefik.http.routers.prefect-ui.tls=true
      - traefik.http.routers.prefect-ui.service=prefect

      # Prefect server listens on 4200
      - traefik.http.services.prefect.loadbalancer.server.port=4200

    networks:
      - traefik

networks:
  traefik:
    external: true
In this model: - Browser visits
<https://my-app.com/prefect-ui>
- Prefect serves the UI under
/prefect-ui
- UI calls API at
<https://my-app.com/api>
But this only works if something routes
/api
to the Prefect API. If
/api
is already your app’s API, don’t use this unless your app proxies those Prefect API calls onward. --- Option 2: UI at
/prefect-ui
, API at
/prefect-api
This is often simpler and avoids conflicts with your application’s own
/api
. Prefect env
Copy code
yaml
environment:
  PREFECT_UI_SERVE_BASE: /prefect-ui
  PREFECT_UI_API_URL: <https://my-app.com/prefect-api>
Traefik labels
Copy code
yaml
services:
  prefect:
    image: prefecthq/prefect:2.20.0-python3.11
    command: prefect server start --host 0.0.0.0 --port 4200
    environment:
      PREFECT_UI_SERVE_BASE: /prefect-ui
      PREFECT_UI_API_URL: <https://my-app.com/prefect-api>
    labels:
      - traefik.enable=true

      # UI route
      - traefik.http.routers.prefect-ui.rule=Host(`<http://my-app.com|my-app.com>`) && PathPrefix(`/prefect-ui`)
      - traefik.http.routers.prefect-ui.entrypoints=websecure
      - traefik.http.routers.prefect-ui.tls=true
      - traefik.http.routers.prefect-ui.service=prefect

      # API route
      - traefik.http.routers.prefect-api.rule=Host(`<http://my-app.com|my-app.com>`) && PathPrefix(`/prefect-api`)
      - traefik.http.routers.prefect-api.entrypoints=websecure
      - traefik.http.routers.prefect-api.tls=true
      - traefik.http.routers.prefect-api.service=prefect

      - traefik.http.services.prefect.loadbalancer.server.port=4200

    networks:
      - traefik

networks:
  traefik:
    external: true
This gives you: - UI:
<https://my-app.com/prefect-ui>
- API:
<https://my-app.com/prefect-api>
That’s usually the least confusing option. --- Do you need
StripPrefix
?
Usually, I would avoid
StripPrefix
here
unless you’ve tested it carefully. Since Prefect is explicitly configured with:
Copy code
bash
PREFECT_UI_SERVE_BASE=/prefect-ui
it’s best if requests arrive in a way consistent with that external path. So prefer: - `PathPrefix(
/prefect-ui
)` - no stripping If you strip the prefix, the app may no longer see paths the way its UI config expects. --- Minimal static Traefik file example If you prefer file-based Traefik config instead of labels: ```yaml http: routers: prefect-ui: rule: "Host(
<http://my-app.com|my-app.com>
) && PathPrefix(
/prefect-ui
)" service: prefect entryPoints: - websecure
tls: {} prefect-api: rule: "Host(
<http://my-app.com|my-app.com>
) && PathPrefix(
/prefect-api
)" service: prefect entryPoints: - websecure tls: {} services: prefect: loadBalancer: servers: - url: "http://prefect:4200"
Copy code
And then set:

```bash
PREFECT_UI_SERVE_BASE=/prefect-ui
PREFECT_UI_API_URL=<https://my-app.com/prefect-api>
--- How to verify After starting, test:
Copy code
bash
curl -i <https://my-app.com/prefect-ui/ui-settings>
You should see JSON containing your configured API URL. Then open:
Copy code
text
<https://my-app.com/prefect-ui>
If the UI loads but API calls fail, the usual cause is: -
PREFECT_UI_API_URL
points to the wrong public URL, or - Traefik is not routing the API path to Prefect --- CLI note I verified
prefect server start
exists in 2.20 and supports the expected flags: -
--host
-
--port
-
--ui
So this command is valid:
Copy code
bash
prefect server start --host 0.0.0.0 --port 4200
--- Useful links - Prefect repo: github.com/PrefectHQ/prefect - Prefect 2 docs landing page: docs-2.prefect.io If you want, I can also give you a full docker-compose example with Traefik + Prefect + Postgres for copy/paste.
f
@Marvin How is this different in Prefect 3?
m
thought for 110.9 seconds
The main difference in Prefect 3 is that the same idea is still supported, but the configuration is a bit more structured and a little more flexible. Short version - Prefect 2.20: use
PREFECT_UI_SERVE_BASE
and
PREFECT_UI_API_URL
- Prefect 3.x: those still work, but Prefect 3 also has the newer canonical
PREFECT_SERVER_UI_*
names and better internal handling for UI routing So for your use case, the concept is not fundamentally different: - UI can still live at
/prefect-ui
- reverse proxy can still expose Prefect under a subpath - you still need to make sure the UI knows the correct public API URL --- In Prefect 2.20 Typical settings:
Copy code
bash
PREFECT_UI_SERVE_BASE=/prefect-ui
PREFECT_UI_API_URL=<https://my-app.com/prefect-api>
--- In Prefect 3.x Preferred settings are:
Copy code
bash
PREFECT_SERVER_UI_SERVE_BASE=/prefect-ui
PREFECT_SERVER_UI_API_URL=<https://my-app.com/prefect-api>
But for compatibility, the old names still work too:
Copy code
bash
PREFECT_UI_SERVE_BASE=/prefect-ui
PREFECT_UI_API_URL=<https://my-app.com/prefect-api>
So if you upgrade from 2.20 to 3.x, your existing env vars will likely still work. --- What improved in Prefect 3 1. New canonical setting names Prefect 3 organizes server settings under
PREFECT_SERVER_*
, so UI settings are more explicitly server-related. 2. Better default API URL behavior In 2.x, the UI often fell back to
/api
. In 3.x, API URL resolution is smarter and can derive from other configured API settings. 3. Better path handling internally Prefect 3 has more robust normalization of subpaths and routing behavior. 4. TOML-based config support In 3.x, you can also manage this in config files more cleanly, not just env vars. --- What does not really change Your Traefik strategy is basically the same: - route `PathPrefix(
/prefect-ui
)` to Prefect - set Prefect’s UI serve base to
/prefect-ui
- set the API URL to the externally reachable API path - avoid unnecessary prefix stripping unless you’ve tested it carefully --- Example for Prefect 3
Copy code
yaml
environment:
  PREFECT_SERVER_UI_SERVE_BASE: /prefect-ui
  PREFECT_SERVER_UI_API_URL: <https://my-app.com/prefect-api>
And Traefik routing still looks conceptually like:
Copy code
yaml
- traefik.http.routers.prefect-ui.rule=Host(`<http://my-app.com|my-app.com>`) && PathPrefix(`/prefect-ui`)
- traefik.http.routers.prefect-api.rule=Host(`<http://my-app.com|my-app.com>`) && PathPrefix(`/prefect-api`)
--- CLI note
prefect server start
still exists in Prefect 3. I verified the command family in your earlier 2.x context, and in 3.x the server-start workflow remains the right approach for self-hosting. --- One important migration-related note If you move from 2.x to 3.x, the biggest differences are not reverse proxying — they’re more around deployments and workers. For example, in 3.x: -
prefect deployment build
is removed - use
prefect deploy
or
flow.from_source(...).deploy(...)
instead That’s unrelated to UI proxying, but it’s usually the bigger upgrade gotcha. --- Bottom line For your exact use case, the difference is mostly: - Prefect 2.20:
PREFECT_UI_*
- Prefect 3.x: prefer
PREFECT_SERVER_UI_*
, but old names still work and the reverse-proxy pattern with Traefik stays almost the same. If you want, I can next give you a side-by-side Traefik + docker-compose example for Prefect 2.20 vs Prefect 3 so you can compare them directly.