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.
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. |
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.
via doctor
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.
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.
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.
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:
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.
| 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:
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.
| 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 for the diagnostic surface, or Secrets and config for the workload identity flow.