> For the complete documentation index, see [llms.txt](https://docs.dorg.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dorg.pro/dorg-architecture/network-topology.md).

# Network Topology

### 1) Network topology

The platform uses a **hub-and-spoke** layout:

| Role                 | VNet                | CIDR          |
| -------------------- | ------------------- | ------------- |
| Hub                  | `vnet-dorg`         | `10.0.0.0/16` |
| Spoke — Auth         | `vnet-auth`         | `10.1.0.0/16` |
| Spoke — Metrics      | `vnet-metrics`      | `10.2.0.0/16` |
| Spoke — RAG          | `vnet-rag`          | `10.3.0.0/16` |
| Spoke — Internal MCP | `vnet-internal-mcp` | `10.4.0.0/16` |

Each spoke is peered **bidirectionally** with the hub, with `allowVirtualNetworkAccess` and `allowForwardedTraffic` enabled.

***

### 2) Subnet segmentation

#### Hub (`vnet-dorg`)

| Subnet           | CIDR          | Purpose                                      |
| ---------------- | ------------- | -------------------------------------------- |
| `snet-aca-dorg`  | `10.0.0.0/23` | Container Apps (orchestrator, hub workloads) |
| `snet-dorg-data` | `10.0.2.0/24` | Private endpoints / data services            |

#### Auth (`vnet-auth`)

| Subnet           | CIDR          |
| ---------------- | ------------- |
| `snet-aca-auth`  | `10.1.0.0/23` |
| `snet-psql-auth` | `10.1.2.0/24` |

#### Metrics (`vnet-metrics`)

| Subnet              | CIDR          |
| ------------------- | ------------- |
| `snet-aca-metrics`  | `10.2.0.0/23` |
| `snet-psql-metrics` | `10.2.2.0/24` |

#### RAG (`vnet-rag`)

| Subnet         | CIDR          |
| -------------- | ------------- |
| `snet-aca-rag` | `10.3.0.0/23` |

#### Internal MCP (`vnet-internal-mcp`)

| Subnet                  | CIDR          |
| ----------------------- | ------------- |
| `snet-aca-internal-mcp` | `10.4.0.0/23` |
| `snet-psql-mcp`         | `10.4.2.0/24` |

**Delegations**

* PostgreSQL subnets → `Microsoft.DBforPostgreSQL/flexibleServers`
* ACA subnets → `Microsoft.App/environments`

***

### 3) Front Door: exposed services

Front Door is **centralized in `core`**: one global endpoint (`<name>.azurefd.net`), one wildcard custom domain (`*.{baseDomain}`), a catch-all route (`/*`), and a **shared rule set**.

Each app stack adds rules via **`createFrontDoorRoute(...)`** in `shared/frontdoor.ts`:

* **Host** matching uses the HTTP `Host` header (equality, lowercase transform).
* Optionally **URL path** (`pathPrefix`) and **`matchProcessingBehavior`** (e.g. `Stop` so later rules do not override a match) — used by the **Console** `/api` route (origin: **Dashboard Gateway** container app).

TLS is terminated on Front Door (managed certificate on the wildcard domain), HTTPS redirect is enforced, and traffic is forwarded to the selected origin over HTTPS.

If **no** host (and path) rule matches, traffic falls back to the **default origin** in `core` (static storage serving 404-style content).

#### Public services (internet clients)

| Service          | Hostname pattern                                                                                               | Source stack        | Health probe        |
| ---------------- | -------------------------------------------------------------------------------------------------------------- | ------------------- | ------------------- |
| Auth / Keycloak  | `{AUTH_SUBDOMAIN}.{DNS_BASE_DOMAIN}` (e.g. `auth.<domain>`)                                                    | `apps/auth`         | `GET /health/ready` |
| Orchestrator API | `{ORCHESTRATOR_SUBDOMAIN}.{DNS_BASE_DOMAIN}` (e.g. `api.<domain>`)                                             | `apps/orchestrator` | `GET /healthz`      |
| Grafana          | `{GRAFANA_SUBDOMAIN}.{DNS_BASE_DOMAIN}`                                                                        | `apps/metrics`      | `HEAD /robots.txt`  |
| Console          | `{DASHBOARD_SUBDOMAIN}.{DNS_BASE_DOMAIN}` (default subdomain `console`; config key retains `dashboard` prefix) | `apps/dashboard`    | See below           |

**Console** registers **two** rules on the **same** hostname:

1. **Dashboard Gateway** (BFF) — `pathPrefix: /api`, origin = Dashboard Gateway container app FQDN, probe `GET /healthz`, `matchProcessingBehavior: Stop` so the catch-all rule does not capture `/api` traffic.
2. **Dashboard Web** (SPA) — no path prefix (remaining paths), origin = Dashboard Web container app FQDN, probe `GET /`.

Clients use `https://<subdomain>.<domain>` as for other services.

#### Not exposed through Front Door

* **Shared internal MCP** (`mcp-365`, `mcp-db`, `mcp-playwright`): internal ACA in `vnet-internal-mcp`, private DNS only; callers are internal workloads (primarily orchestrator).
* **RAG MCP** (`mcp-rag`): separate **internal** ACA environment on **`snet-aca-rag`** in **`vnet-rag`** (not the shared `vnet-internal-mcp` env). It uses its **own** private DNS zone (environment default domain) with links so the hub (orchestrator) can resolve it. Still not a public Front Door target.

***

### 4) Ingress and access controls

* **NSGs** on ACA-facing subnets allow inbound **HTTP/HTTPS** from **`AzureFrontDoor.Backend`** where configured for public apps.
* **Database NSGs** allow PostgreSQL **`5432`** from approved internal sources (VNet prefixes, per subnet — see `core/index.ts` NSG definitions).

***

### 5) Internal MCP DNS and reachability (shared env)

The **shared** internal MCP Container Apps environment is created in **`vnet-internal-mcp`** with **`internal: true`**.

* A **private DNS zone** is created using that environment’s **default domain**.
* A **wildcard `A`** record points to the environment **static IP**.
* **Virtual network links** attach the zone to:
  * `vnet-dorg`
  * `vnet-internal-mcp`

That lets the orchestrator (and other hub workloads) resolve and reach **mcp-365**, **mcp-db**, and **mcp-playwright** over private networking.

***

### 5b) RAG internal ACA and DNS (separate from shared MCP)

**RAG** does **not** use the shared `env-internal-mcp` subnet:

* **`apps/mcp-rag`** defines a dedicated internal ACA environment on **`snet-aca-rag`** with **`internal: true`**.
* A **separate** private DNS zone is created from the **RAG** environment default domain, with a wildcard `A` to that env’s static IP.
* DNS is linked to **`vnet-dorg`**, **`vnet-rag`**, and **`vnet-internal-mcp`** so the orchestrator, RAG workloads, and internal MCP workloads can resolve the RAG MCP privately.

This is **in addition to** the internal MCP pattern in §5, not a subset of it.

***

### 5c) Metrics internal ACA and DNS

The metrics stack uses a dedicated internal Container Apps environment:

* **`apps/metrics`** creates a private DNS zone from the **metrics environment default domain**.
* A wildcard `A` record points to the environment static IP.
* DNS is linked to **`vnet-metrics`**, **`vnet-dorg`**, **`vnet-internal-mcp`**, and **`vnet-rag`**.

These links let Grafana, the orchestrator, internal MCP services, and RAG workloads resolve the private endpoints for the OpenTelemetry collector, Loki, and Prometheus.

***

### 6) Private DNS zones and VNet links

The complete deployment creates **6 Azure Private DNS zones** and **16 virtual network links**. The `core` stack creates four zones, while `apps/metrics` and `apps/mcp-rag` create one zone each.

| Private DNS zone                          | Stack          | Purpose                                                                       | Linked VNets                                                  | Links |
| ----------------------------------------- | -------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------- | ----: |
| `privatelink.postgres.database.azure.com` | `core`         | Private resolution for the auth, metrics, and MCP PostgreSQL Flexible Servers | `vnet-auth`, `vnet-metrics`, `vnet-dorg`, `vnet-internal-mcp` |     4 |
| `privatelink.blob.core.windows.net`       | `core`         | Private resolution for the blob storage private endpoint                      | `vnet-dorg`                                                   |     1 |
| `privatelink.mongo.cosmos.azure.com`      | `core`         | Private resolution for the Cosmos DB Mongo API private endpoint               | `vnet-dorg`, `vnet-rag`                                       |     2 |
| Internal MCP environment default domain   | `core`         | Private resolution for `mcp-365`, `mcp-db`, and `mcp-playwright`              | `vnet-dorg`, `vnet-internal-mcp`                              |     2 |
| Metrics environment default domain        | `apps/metrics` | Private resolution for the OpenTelemetry collector, Loki, and Prometheus      | `vnet-metrics`, `vnet-dorg`, `vnet-internal-mcp`, `vnet-rag`  |     4 |
| RAG environment default domain            | `apps/mcp-rag` | Private resolution for the RAG MCP                                            | `vnet-dorg`, `vnet-rag`, `vnet-internal-mcp`                  |     3 |

The three `privatelink.*` zone names follow Azure Private Link conventions. The three Container Apps zone names are dynamic and use the `defaultDomain` generated by Azure for each environment.

#### VNet link inventory

All 16 links use `registrationEnabled: false`; DNS records are managed explicitly rather than registered automatically.

| Link resource                   | Private DNS zone                          | VNet                | Purpose                                                      |
| ------------------------------- | ----------------------------------------- | ------------------- | ------------------------------------------------------------ |
| `env-mcp-dns-link-dorg`         | Internal MCP environment default domain   | `vnet-dorg`         | Hub workloads resolve shared internal MCP services           |
| `env-mcp-dns-link-int`          | Internal MCP environment default domain   | `vnet-internal-mcp` | Shared MCP workloads resolve their local environment         |
| `psql-dns-link-auth`            | `privatelink.postgres.database.azure.com` | `vnet-auth`         | Keycloak resolves its PostgreSQL server                      |
| `psql-dns-link-metrics`         | `privatelink.postgres.database.azure.com` | `vnet-metrics`      | Metrics workloads resolve their PostgreSQL server            |
| `psql-dns-link-dorg`            | `privatelink.postgres.database.azure.com` | `vnet-dorg`         | Hub and operational workloads resolve PostgreSQL servers     |
| `psql-dns-link-mcp`             | `privatelink.postgres.database.azure.com` | `vnet-internal-mcp` | MCP-DB resolves its PostgreSQL server                        |
| `blob-dns-link`                 | `privatelink.blob.core.windows.net`       | `vnet-dorg`         | Hub workloads resolve the blob storage private endpoint      |
| `cosmos-dns-link`               | `privatelink.mongo.cosmos.azure.com`      | `vnet-dorg`         | Hub workloads resolve the Cosmos DB private endpoint         |
| `cosmos-dns-link-rag`           | `privatelink.mongo.cosmos.azure.com`      | `vnet-rag`          | RAG workloads resolve the Cosmos DB private endpoint         |
| `env-metrics-dns-link-metrics`  | Metrics environment default domain        | `vnet-metrics`      | Metrics workloads resolve their local observability services |
| `env-metrics-dns-link-dorg`     | Metrics environment default domain        | `vnet-dorg`         | Grafana and orchestrator resolve observability services      |
| `env-metrics-dns-link-mcp`      | Metrics environment default domain        | `vnet-internal-mcp` | Internal MCP services resolve the telemetry endpoints        |
| `env-metrics-dns-link-rag`      | Metrics environment default domain        | `vnet-rag`          | RAG workloads resolve the telemetry endpoints                |
| `env-rag-dns-link-dorg`         | RAG environment default domain            | `vnet-dorg`         | The orchestrator resolves the RAG MCP                        |
| `env-rag-dns-link-rag`          | RAG environment default domain            | `vnet-rag`          | RAG workloads resolve their local environment                |
| `env-rag-dns-link-internal-mcp` | RAG environment default domain            | `vnet-internal-mcp` | Internal MCP workloads resolve the RAG MCP                   |

The **Cosmos DB (Mongo API)** account uses **virtual network rules** for subnets that need access (including **`snet-aca-rag`** alongside hub ACA/data subnets). The private DNS zone for Cosmos is therefore linked to **both** the hub and the RAG VNet so private endpoint resolution works where those workloads run.

A **storage private endpoint** sits in **`snet-dorg-data`** with a **private DNS zone group** for blob resolution.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.dorg.pro/dorg-architecture/network-topology.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
