# Web Serving Modes

> Choose how the web server handles a request for a path that is not a file on disk: a clean 404, a CMS front controller, or a single-page app fallback.

Source: https://www.corepanel.net/docs/web/serving-modes/
Last updated: 2026-07-30
Part of the CorePanel documentation — https://www.corepanel.net/docs

---

Every domain and subdomain has a **serving mode**. It decides one thing: what happens
when a request arrives for a path that does not exist as a file in the document root.

That single decision is the difference between WordPress permalinks working or 404-ing,
and between a React route reloading correctly or breaking on refresh.

## The three modes

| Mode | A missing path… | Use for |
|---|---|---|
| **Plain** *(default)* | 404s immediately | Static sites and classic PHP sites, where a missing file *is* an error |
| **CMS** | is routed to `/index.php` | WordPress, Laravel, Drupal, Symfony — any front-controller app |
| **SPA** | falls back to `/index.html` | React, Vue, Angular, Svelte builds with client-side routing |

In every mode, an existing file or directory is served directly; the mode only governs
the fallback.

## Why Plain is the default

Because the two ways of guessing wrong are not comparable.

If the site is in Plain mode and it needed CMS, you find out immediately: the home page
works, the first inner link 404s, and one selector fixes it. The failure is loud, local
and cheap.

If it were the other way round — a fallback that serves *something* for every unknown
path — a static site would answer **200 with its home page** for every broken link, every
old URL and every crawler request. Nobody opens a ticket about that. The site just quietly
loses indexing while looking fine.

So the default fails closed: a path that matches no file is reported as missing, because
that is what it is. When CorePanel installs the application itself — [WordPress](https://www.corepanel.net/docs/wordpress),
for instance — it sets **CMS** on that domain for you, so the case where the answer is
actually known does not depend on anyone remembering.

> **There used to be an "Automatic" mode**
>
> It tried `/index.php`, then `/index.html`, then 404. Because every document root is
> created with an `index.html`, the `index.html` step always matched and the 404 was never
> reached — so every broken URL on a static site answered 200 with the home page. It has
> been retired; sites that had it now serve as **Plain**. If one of them is a
> front-controller app, switch it to **CMS**.
## When to change it

- **CMS** — the app routes its own URLs: WordPress with pretty permalinks, Laravel,
  Drupal, Symfony. Set automatically when CorePanel installs the app.
- **SPA** — a client-side-routed build, so a deep link reloads into the app instead of
  404-ing.
- **Plain** — leave it as it is for a static site, or come back to it when a site stops
  being an app.

## Changing the mode

- **On creation** — the *Web mode* field of the account, domain or subdomain form (from
  the CLI, `--web-mode` on `corepanel domain add` and `corepanel subdomain add`).
- **Afterwards** — open the account, go to **Domains** or **Subdomains**, and use the
  edit button on the row. The settings dialog opens with **Web mode** at the top.

![The domain settings dialog for example.com: a Web mode section with Plain, CMS and SPA as selectable cards, each describing what a missing path does, and a Canonical host section below it.](https://www.corepanel.net/_astro/domain-settings-dialog.B8cn54mp.svg)

For a domain, the same dialog also holds its [canonical host](https://www.corepanel.net/docs/accounts/domains);
a subdomain has only the mode, since it answers under a single hostname.

The change is written to the site configuration and applied on reload; no restart, no
downtime.

> **Re-selecting the current mode is not a no-op**
>
> Saving the mode a domain already has re-emits its site file. That makes it a
> "re-apply / reconcile" action — useful if the served configuration has drifted from what
> the panel shows.
## Modes and reverse proxy routes

The serving mode governs the **document root**. A [reverse proxy route](https://www.corepanel.net/docs/reverse-proxy)
takes precedence on the paths it covers: those requests are forwarded to your service and
never reach the fallback. A typical SPA-plus-API domain uses SPA mode for the app plus a
route on `/api/*` for the backend.

## Troubleshooting

| Symptom | Likely cause |
|---|---|
| WordPress home page works, inner pages 404 | The site is in **Plain** mode. Switch to **CMS**. |
| SPA works, reloading a deep link 404s | The site needs the **SPA** fallback. |
| A missing page shows the home page instead of a 404 | The site is in **CMS** or **SPA** mode, and its fallback is doing its job. If you want real 404s on missing paths, use **Plain**. |
| A file that exists is not served | Not a mode problem — check the path, ownership, and that it is under the right document root. |
