Skip to main content

Exposing Apps on Custom Ports

In a Dev Environment you can run any app or service on any port — a FastAPI server, a dashboard, a docs site — and open it straight from your browser. No extra tools or tunnels are needed: VS Code (code-server) automatically forwards every listening port for you.

Development only

This guide is for development environments only. If you want to deploy an app for end users, use Live Apps.

Who does the forwarding?

code-server (the browser-based VS Code that runs inside your Dev Environment) provides VS Code's built-in automatic port forwarding. It detects any port a process starts listening on inside the pod and exposes it through its own /proxy/<port>/ endpoint — that's the Auto Forwarded entry you see in the PORTS tab.

MINEO's proxy simply routes /dev-env/<organization>/<dev-environment>/… to code-server (running on port 8000), keeping MINEO's authentication in front. So a request flows like this:

The forwarded URL follows this pattern:

https://<host>/dev-env/<organization>/<dev-environment>/proxy/<port>/

How to expose a port

  1. Open a terminal in VS Code (Terminal → New Terminal).
  2. Run your app bound to all interfaces (0.0.0.0), on whatever port you like:
    uvicorn app:app --host 0.0.0.0 --port 8888
  3. Open the PORTS tab (next to the terminal). The port appears as Auto Forwarded with a Forwarded Address — click it to open your app, or build the /proxy/<port>/ URL manually.
Bind to 0.0.0.0

Bind your app to 0.0.0.0, not 127.0.0.1. If it only listens on localhost the proxy may not be able to reach it.

Apps that generate absolute URLs

The forwarding above works out of the box for apps that use relative URLs. But apps that build absolute URLs — FastAPI's /docs (Swagger UI), many dashboards and SPAs — assume they are served from the site root. Under the proxy their assets and API calls (/openapi.json, /static/…) resolve to https://<host>/… and return 404, so the page renders blank or unstyled.

Fix it by telling the app the path prefix it is served under. Every Dev Environment exposes that prefix as the environment variable MINEO_LIVE_APP_URL_PATH — its value is /dev-env/<organization>/<dev-environment>/. Append proxy/<port> and pass it to your framework's base-path setting.

For FastAPI, that setting is root_path:

import os
from fastapi import FastAPI

PORT = 8888
base = os.environ.get("MINEO_LIVE_APP_URL_PATH", "/").rstrip("/") # /dev-env/<org>/<dev-env>
app = FastAPI(root_path=f"{base}/proxy/{PORT}") # …/proxy/8888

Run it and open …/proxy/<port>/docs: Swagger UI now loads, because the app generates its absolute URLs with the full prefix.

FrameworkBase-path setting
FastAPIFastAPI(root_path=…)
Streamlit--server.baseUrlPath=…
Plain JS / SPAthe framework's base / publicPath build option
MINEO_LIVE_APP_URL_PATH

The same variable is also injected into Live Apps, where its value is /live-app/<org>/<app>/ and the app runs on port 8000 — there you use it as root_path directly. In a Dev Environment it is only the base path, so append proxy/<port> because your app is reached through code-server's port proxy.

Prefer /proxy/ + root_path over /absproxy/

code-server also exposes an /absproxy/<port>/ path that passes the URL through unchanged. Avoid it for apps like FastAPI: it does not strip the prefix, so your routes (/, /docs) stop matching unless you mount the whole app under that sub-path. Sticking with /proxy/<port>/ (the URL shown in the PORTS tab) plus root_path is cleaner — the proxy strips the prefix so routing just works, and root_path handles URL generation. Reserve /absproxy/ for apps that cannot be told a base path.

Learn more