# Building and Hosting an App in DKubeX Workspace with a Coding Agent Once you have a coding agent running in DKubeX Workspace, you can have it build an app and host it straight from the workspace — reachable in the browser through the workspace's built-in reverse proxy. This tutorial walks through it end to end using a **data-analysis workbench** as the worked example, but the same flow builds and hosts any app. The flow is two steps. First you give the agent the workspace's app-hosting rules **once**, as standing instructions. Then you describe your app in plain language — the agent applies the hosting rules for you, so your app prompts stay focused on what the app does, not on how the proxy works. To get a coding agent set up first, see [Using Claude Code in DKubeX Workspace with a Claude subscription](./using-claude-code-in-dkubex-workspace-with-a-claude-subscription.md) or [Using Claude Code in DKubeX Workspace with DKubeX or cloud provider models](./using-claude-code-in-dkubex-workspace-with-dkubex-or-cloud-provider-models.md). ## Prerequisites - A running DKubeX Workspace. - A coding agent set up in the workspace — Claude Code, Codex, OpenCode, Copilot CLI, Antigravity, Mistral Vibe, or Hermes. See the two tutorials linked above. ## How app hosting works Every workspace has an **nginx reverse proxy**. When you start a web server on a port inside the workspace, it becomes reachable at: ``` https:///workspace/// ``` One thing determines whether your app works through that URL: :::{note} **nginx does *not* strip the `/workspace//` prefix before forwarding.** It proxies straight to `127.0.0.1:` with the full path intact — your app receives requests for `/workspace///...`, not `/...`. An app that only knows how to serve `/` will 404 on every request through the public URL, even though `curl localhost:/` works fine from inside the workspace. So both sides of your app must be **prefix-aware** — the backend must mount its routes under the prefix, and the frontend must load its assets and call its APIs under the prefix too. Getting either side wrong is the single most common reason a newly built app "works when I test it locally but 404s in the browser." Rather than restate these rules in every app prompt, you load them once as standing instructions (Step 2). The full rule set lives in a single file, `APP_HOSTING.md`, that the agent reads and follows for everything it builds in the workspace. ::: ## Step 1 — Open a coding agent From the workspace launcher, open a coding agent (for example, **Claude Code**). Any of the agents work: | Agent | Best for | | --- | --- | | **Claude Code** | Full-stack apps, complex logic | | **Codex** | Quick prototyping, OpenAI models | | **OpenCode** | Open-source model workflows | | **Copilot CLI** | GitHub-integrated development | | **Antigravity** | Google model exploration | | **Mistral Vibe** | Mistral-powered coding | | **Hermes** | Nous Research models | ## Step 2 — Load the app-hosting rules as standing instructions Give the agent the workspace's app-hosting rules before you ask it to build anything. Fetch the file with `wget`, or paste its contents in directly if the workspace can't reach GitHub. ::::{tab-set} :::{tab-item} Download with wget Run this in the workspace terminal — or ask the agent to run it for you — to pull the rules file into your home directory: ```bash wget https://raw.githubusercontent.com/dkubeio/docs-site/app-hosting-example/APP_HOSTING.md ``` Then tell the agent to adopt it as standing instructions: ``` Read the file APP_HOSTING.md in my home directory. Treat it as your standing instructions for hosting apps in this workspace — follow these rules for every app you build here. ``` ::: :::{tab-item} Copy and paste Paste the following directly into the agent — the framing line followed by the full rules: ```` Here are the app-hosting rules for this workspace. Treat them as your standing instructions and follow them for every app you build here: # Hosting Apps in Your DKubeX Workspace This guide covers how app hosting works in this workspace, and the rules any app needs to follow to work behind the workspace's reverse proxy — regardless of which app you're building or which coding agent you use to build it. ## Prerequisites - A running DKubeX Workspace - A coding model deployed via SecureLLM (the platform configures agents automatically) ## How App Hosting Works Every workspace has an nginx reverse proxy. When you start any web server on a port inside the workspace, it becomes accessible at: ``` https:///workspace/// ``` **Important: nginx does NOT strip that prefix before forwarding to your app.** It proxies straight to `127.0.0.1:` with the full path intact — your app receives requests for `/workspace///...`, not `/...`. An app that only knows how to serve `/` will 404 on every real request through the public URL, even though `curl localhost:/` works fine from inside the workspace. This means both the **backend** and the **frontend** must be prefix-aware: - **Backend:** All API routes and the HTML-serving route must be mounted under the prefix path so the server recognizes incoming requests — see Rule 1. - **Frontend:** The HTML page must load all assets (stylesheets, scripts, images) and navigate to other pages using the correct prefix — see Rule 2. A single inline page with no external assets may work with just relative URLs, but multi-page apps or apps that load separate asset files will break without proper prefix configuration. Getting either side wrong is the single most common reason a newly built app "works when I test it locally but 404s in the browser." --- ## Step-by-Step: Build and Host Any App ### Step 1 — Open a Coding Agent From the workspace launcher, click any agent card: | Agent | Best for | |-------|----------| | **Claude Code** | Full-stack apps, complex logic | | **Codex** | Quick prototyping, OpenAI models | | **OpenCode** | Open-source model workflows | | **Copilot** | GitHub-integrated development | | **Antigravity** | Google model exploration | | **Vibe** | Mistral-powered coding | | **Hermes** | Nous Research models | ### Step 2 — Ask the Agent to Build Your App Create a project directory first, then give the agent a prompt describing your app. **Always include the rules below** in your prompt so the agent builds something that actually works behind the proxy. ### Step 3 — Install Dependencies and Run The agent will typically include install instructions. If not: ```bash # Python apps python3 -m venv .venv ./.venv/bin/pip install -r requirements.txt ./.venv/bin/python app.py # Node.js apps npm install node server.js ``` Keep it running after closing the agent terminal: ```bash nohup ./.venv/bin/python app.py > app.log 2>&1 & disown ``` ### Step 4 — Access Your App Open a browser and go to: ``` https:///workspace/// ``` For example, if your app runs on port 8501: ``` https://dkubex.example.com/workspace/johndoe/8501/ ``` --- ## Rules for Workspace-Compatible Apps These rules ensure your app works behind the workspace's nginx proxy. **Include them in your prompt to the coding agent** so it builds the app correctly. 1. **Mount backend routes under the workspace prefix — nginx doesn't strip it.** Every request your app receives arrives with the full path: `/workspace///api/data`, not `/api/data`. Your backend must expect routes at that prefix. For FastAPI, use `APIRouter(prefix=...)` instead of defining routes directly on the app: ```python import os from fastapi import FastAPI, APIRouter # Build prefix from workspace env vars (pre-configured by the platform) PATH_PREFIX = "/workspace/{}/{}".format( os.environ.get("USERNAME", "user"), os.environ.get("APP_PORT", "8501"), ) app = FastAPI() router = APIRouter(prefix=PATH_PREFIX) @router.get("/api/data") async def get_data(): return {"items": []} # Serve the HTML page under the prefix too @router.get("/") async def index(): return HTMLResponse(html_content) app.include_router(router) ``` This way the app natively serves at `/workspace///...` with no custom middleware. For Express, use `app.use(PATH_PREFIX, router)`; for Flask, use `Blueprint` with `url_prefix`. Tell your coding agent to use this pattern explicitly — it's easy to skip if you only test against `localhost:` directly, since that always works regardless. 2. **Frontend must also be prefix-aware.** Your app's UI is served from `/workspace///`, not `/`. Every URL the browser loads — stylesheets, scripts, images, page navigations, API calls — must resolve under that prefix. There are two approaches: **Option A — `` tag (simplest for single-file / inline apps):** Set a `` in your HTML `` so the browser resolves all relative URLs from the prefix path: ```html ``` Then use relative URLs everywhere — `fetch('api/data')`, ``, ``, ``. For a FastAPI app, inject the prefix dynamically so it works for any user/port: ```python html_content = f""" """ ``` **Option B — Framework prefix config (for React, Vue, Vite, etc.):** | Framework | Setting | |-----------|---------| | Vite | `base: '/workspace/user/port/'` in `vite.config.js` | | React Router | `` | | Vue Router | `createRouter({ history: createWebHistory('/workspace/user/port') })` | | Next.js | `basePath: '/workspace/user/port'` in `next.config.js` | **What breaks without prefix configuration:** | What | Wrong (absolute) | Right (relative, with base href or prefix) | |------|-------------------|---------------------------------------------| | API fetch | `fetch('/api/data')` | `fetch('api/data')` | | Stylesheet | `` | `` | | Script | `