Via

TLS, routing, and the proxy

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.

SurfaceBehavior
Base domainServes Via API, auth, Git, and well-known metadata paths.
App domainsRoutes approved hostnames to the app's current healthy runtime target.
Path routesRoutes approved path prefixes on the base domain to app runtime targets.
Unknown host/pathReturns 404 vary: route not found.
Known app without a healthy runtimeReturns the Via maintenance response with HTTP 502.

Tracking the proxy

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

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:

RouteUpstream
/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.

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:

GateMeaning
Domain policyThe hostname must match operator-owned policy that allows app claims.
Ownership proofThe app-domain request must be verified, usually by TXT proof.
ApprovalPolicies with human review require operator approval before routing.
Certificate coverageThe effective certificate must cover the hostname.
Route validationHostname/path conflicts, target service, and port rules must pass.
Load-balancer applyPOST /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.

Health and failure behaviour

ScenarioBehavior
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 RUNNINGNew container takes over routing; prior runtime is stopped and prior deploy moves to SUPERSEDED.
Deploy reaches FAILEDNever written into routing. Previous healthy deploy continues to serve.
App has no healthy successorApp subdomain serves a Via-branded 502 maintenance response.
App exists with no deploy ever reaching RUNNINGSame 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:

ReasonTrigger
no deploy has reached running state yetApp registered but never reached RUNNING.
the running container is no longer reachableRuntime 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

LimitationMitigation
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.

← Certificates
Add-ons →