
<div class="callout callout-attn"><p><strong>Alpha.</strong> VIA is under active development. APIs, operational flows, and host requirements may change between releases.</p></div>

Via public traffic goes through HTTPS termination, route application, and the maintenance response shown when no healthy app runtime is available.

Operator examples assume `via install` has added your host user to the Via
admin/shared group. Reconnect or run `newgrp vary` after first install so the
membership is active in your shell.

## Proxy surface

Via owns the public proxy for the server domain and app routes. The proxy accepts HTTPS traffic, reserves Via control-plane paths, publishes validated app routes, and returns a clear maintenance response when a known app route has no healthy runtime target.

Operators should change routing through Via domain, certificate, route, deploy, and repair commands. Hand-edited proxy files are overwritten when Via regenerates routing state.

| Surface | Behavior |
|---|---|
| Base domain | Serves Via API, auth, Git, and well-known metadata paths. |
| App domains | Routes approved hostnames to the app's current healthy runtime target. |
| Path routes | Routes approved path prefixes on the base domain to app runtime targets. |
| Unknown host/path | Returns `404 vary: route not found`. |
| Known app without a healthy runtime | Returns the Via maintenance response with HTTP 502. |

### Tracking the proxy

```bash
via status
# ...
#   proxy active
```

The proxy status line reports whether the managed proxy service is installed and active. Use `via doctor` for higher-level route, certificate, and reachability checks.

```bash
via doctor
```

### Skipping the proxy

The managed proxy can be deferred during install for a host that will temporarily use a different public ingress path. The other components install and start as usual; `via status` reports the proxy line as `not installed`.

`via uninstall --yes` removes the managed proxy service and Via-owned proxy config along with the other Via-managed unit files. Run `via uninstall --keep-data --yes` if you need to preserve `/var/lib/via/`, including proxy runtime data.

## HTTPS termination

`via init --domain <d>` configures HTTPS for the server domain. The proxy reserves four Via route families for the control plane:

| Route                     | Upstream                       |
|---------------------------|--------------------------------|
| `/api/*`                  | `127.0.0.1:<server.port>`     |
| `/git/*`                  | `127.0.0.1:<server.port>`     |
| `/auth/*`                 | `127.0.0.1:<server.port>`     |
| `/.well-known/vary/*`     | `127.0.0.1:<server.port>`     |

Anything that does not match a reserved route returns `404 vary: route not found`. App routes are added after the domain, certificate, and route gates pass.

Certificate strategy is documented separately: public ACME, private/internal certificates, uploaded certificates, domain defaults, per-route certificate IDs, and renewal checks are covered in [Certificates](/docs/via/certificates/).

### Hand-edit policy

Generated proxy config starts with a `do not hand-edit` banner. Edits made by hand are lost the next time `via init` runs or the next time a deploy reaches `RUNNING`, because the runner regenerates routes from control-plane state. Change routing through app manifests, Via domain approval, and route repair commands rather than editing generated files.

## Validated app routing

Public app routes are stored as route resources. A successful deploy gives the app a runtime target. It does not grant authority over arbitrary hostnames. In the normal app-owner path, `vary app deploy --apply-manifest` creates or reuses route resources from `via.app.toml`; route repair commands are reserved for operators and advanced automation.

Before a route can be applied, it must pass these gates:

| Gate | Meaning |
|---|---|
| Domain policy | The hostname must match operator-owned policy that allows app claims. |
| Ownership proof | The app-domain request must be verified, usually by TXT proof. |
| Approval | Policies with human review require operator approval before routing. |
| Certificate coverage | The effective certificate must cover the hostname. |
| Route validation | Hostname/path conflicts, target service, and port rules must pass. |
| Load-balancer apply | `POST /v1/load-balancer/reload` records the apply operation and updates route state. |

For each active app route whose app has a running runtime target, the proxy routes either the approved hostname or approved path prefix to that runtime. Certificate selection comes from the route and domain policy. App-owner APIs never expose private keys, PEM material, ACME account keys, or storage paths. Operators must point an `A`/`AAAA` record or `CNAME` at the host for the hostname to resolve.

Routes without a healthy current deploy are not rendered as live upstreams. A superseded or failed container disappears from routing on the next regenerate. Re-running with no state change writes nothing and triggers no reload.

The control plane records route validation and proxy apply operations. A proxy apply failure marks route state as failed instead of claiming traffic is active. To force a reload by hand:

```bash
via load-balancer reload
```

`vary app status`, `vary app inspect`, and the app route API surface route state, validation errors, effective certificate id, active operation id, and load-balancer apply state.

## Health and failure behaviour

| Scenario                                          | Behavior                                                                                      |
|---------------------------------------------------|-----------------------------------------------------------------------------------------------|
| New deploy in flight (DEPLOYING / failed verification) | Prior healthy deploy continues to serve. `apps.current_deploy_id` only flips when the new deploy reaches `RUNNING`. |
| New deploy reaches RUNNING                        | New container takes over routing; prior runtime is stopped and prior deploy moves to `SUPERSEDED`. |
| Deploy reaches FAILED                             | Never written into routing. Previous healthy deploy continues to serve.                       |
| App has no healthy successor                      | App subdomain serves a Via-branded 502 maintenance response.                                  |
| App exists with no deploy ever reaching RUNNING   | Same maintenance response, with `reason = "no deploy has reached running state yet"`.         |

For each app in the maintenance set, the renderer emits both a subdomain block and a path-prefix block returning HTTP 502 with body:

```text
Via: application unavailable (app=<name>, reason=<detail>)
```

`<detail>` is one of:

| Reason                                                  | Trigger                                                       |
|---------------------------------------------------------|---------------------------------------------------------------|
| `no deploy has reached running state yet`               | App registered but never reached `RUNNING`.                   |
| `the running container is no longer reachable`          | Runtime instance was marked stopped / superseded with no successor. |

The 502 status means the proxy found a route for the hostname, but the upstream is unavailable. A typo or unknown hostname still gets a 404.

### Limitations

| Limitation                                              | Mitigation                                                              |
|---------------------------------------------------------|-------------------------------------------------------------------------|
| Silent crash detection is not implemented.              | An operator who notices `vary app status` showing a running deploy with no responding container can manually mark the runtime stopped (or push a fresh deploy). |
| Maintenance routes are eventually consistent.           | They are rewritten on every successful launch hook and on `via start`; there is no per-second polling of app health. |

Continue to [Operations](/docs/via/operations/) for the diagnostic surface, or [Secrets and config](/docs/via/secrets-and-config/) for the workload identity flow.
