---
title: web
description: The server-rendered dashboard. Port 3000.
---

The server calls `api` at `API_ORIGIN`; the browser calls it directly at `PUBLIC_API_ORIGIN`. Set the same `APP_DASHBOARD_ORIGIN` here and in [api](/self-hosting/services/api).

| Variable               | Required | Default                 | Description                                    |
| ---------------------- | :------: | ----------------------- | ---------------------------------------------- |
| `APP_DASHBOARD_ORIGIN` |   yes    |                         | Dashboard origin. Same value as in `api`.      |
| `API_ORIGIN`           |    no    | `http://localhost:4000` | Where the server reaches `api`.                |
| `PUBLIC_API_ORIGIN`    |    no    | `API_ORIGIN`            | Where browsers reach `api`, when it differs.   |
| `INGEST_ORIGIN`        |    no    | `http://localhost:4100` | Intake origin shown in project setup snippets. |
| `PUBLIC_INGEST_ORIGIN` |    no    | `INGEST_ORIGIN`         | Overrides `INGEST_ORIGIN` in the snippets.     |
| `MCP_ORIGIN`           |    no    | `http://localhost:4500` | MCP origin shown in the API settings.          |
| `PORT`                 |    no    | `3000`                  | HTTP port.                                     |

Unlike the other services, `web` treats an empty origin as unset.

Every response sets `X-Frame-Options: DENY` and a `Content-Security-Policy` that allows requests only to the dashboard and the browser's API origin. If browsers reach `api` at another address than `API_ORIGIN`, set `PUBLIC_API_ORIGIN`, or the policy blocks every call. It also sets `X-Content-Type-Options: nosniff`, `Referrer-Policy: strict-origin-when-cross-origin`, a `Permissions-Policy` that turns off the camera, microphone, geolocation, payment and USB, and `Strict-Transport-Security` for one year on the dashboard host only. A proxy in front of `web` must keep these headers.
