# Run serving activation Each Run uses `https://run-.`. Its **Open** link opens that address in its own tab. Project-only applications enter the enrolled login flow. [ADR 0069](../../../../docs/decisions/0069-project-private-run-services.md) defines the authority and Project boundary. Service actions default to Project-only access. `options.exposure: public` publishes the newly launched Run for anonymous callers. Both applications and inference services use the same isolated URL, gateway and native identity checks. Public callers need no platform login. Private callers use the existing login and current Project permission checks. Changing an action affects new Runs; stop an existing Run to withdraw its endpoint. ## Site configuration Serving is optional. Add this block to the distributed environment policy with the Site's reviewed names: ```yaml serving: enabled: true domain: apps.example.org login_origin: https://platform.example.org ``` The login origin must be an enrolled `pharos` or `themelio-compat` origin. Choose the one where members already sign in, because the authorise step reads that origin's session. Themelio routes `/auth/run-services/` to the API with its public Host (`themelio-compat/api-auth/web.conf`). API authentication, application delivery and the Site Agent must be enabled. The serving suffix must exclude every platform origin. A separate registrable domain also avoids sharing browser site-level cookie boundaries with platform services. Point wildcard DNS at the Site edge. Provision its matching wildcard certificate through the Site's DNS-capable issuer. The edge's HTTP-01 issuer continues to handle ordinary platform hosts. In certbot mode, supply the wildcard in private inventory: ```yaml edge_serving_certificate_files: '*.apps.example.org': certificate: /etc/serving-tls/fullchain.pem key: /etc/serving-tls/privkey.pem ``` In existing-certificate mode, add this entry to `edge_certificate_files` alongside the other hosts. That issuer owns renewal and subsequent edge reloads. ### Icarus staging The `icarus-cloud` policy enables serving under `apps.staging.pharosfactory.ai`, with login through Themelio, `https://themelio.staging.pharosfactory.ai`. A Run opens at `https://run-.apps.staging.pharosfactory.ai`. Wildcard DNS must reach the staging edge at `147.102.227.50`. The [staging DNS and serving runbook](../../../../devops/runbooks/staging-acme-dns.md) is the repository-owned installation path: delegated BIND DNS, ACME issuance, automatic edge binding and the private transport credential role. Before delivery, apply the DNS and credential roles below. The edge automatically reads the matching DNS issuer's certificate paths. For a separate certificate owner, use the explicit inventory binding above. Deliver the complete integration revision containing the serving policy. Record the deployed revision and qualify fresh member Runs before marking the staging acceptance cases as passed. #### Operator hand-off Run this procedure through Icarus's existing administration runner, using its private inventory, administrator kubeconfig and deployment state. The operator needs authorised sudo on the edge and access to the DNS challenge owner. Keep the runner account unprivileged. Use a clean checkout of the agreed integration revision containing this policy and record its full SHA before deployment. 1. **Capture the installed state.** Follow the [distributed input guide](../../../../docs/distributed-setup.md#inputs-on-one-administration-machine) to locate the existing runner binding and private paths. Record the deployed revision, cluster identity, Argo health and current edge configuration. Reuse the environment's deployment lock. Preserve existing applications, provider credentials, Runtime journals and the adopted foundation. 2. **Prepare DNS and the wildcard certificate.** Follow sections A and B of the [staging runbook](../../../../devops/runbooks/staging-acme-dns.md). Apply the committed `acme-dns.yml` playbook, verify external UDP and TCP authority, add the GoDaddy delegation and issue the apex/wildcard certificate. The role preserves the issuer's private state across reapplication. 3. **Verify renewal and edge binding.** Confirm `pharos-acme-renew.timer` is enabled and its dry run succeeds. The edge role reads the issuer's root-owned settings and adopts its exact certificate paths. The renewal controller validates Nginx before reloading it. Reapply the DNS role to check recovery and credential preservation. 4. **Install the private transport pair.** Follow section C of the staging runbook and apply `run-serving-credentials.yml` with the administrator's explicit kubeconfig and reviewed cluster UID. Import an existing matching private directory when necessary. The role generates and installs both Secrets, preserves the issuer and key, and enables renewal and interrupted rollout recovery. Its CA signing key stays on the administrator host. 5. **Refresh the policy review and deliver.** Use `make deploy-plan` and `make cutover-plan` with `ENV=icarus-cloud` and the actual private paths on the recorded runner. Review the new source, input and topology fingerprints before setting `approved: true` in its private `cutover.json`. Follow the **later policy change** procedure in [Record the approved foundation](../../../../devops/runbooks/icarus-cloud-cutover.md#record-the-approved-foundation): `make foundation-adopt`, then `make deploy`, with the same environment and private inputs. This refreshes the existing adoption; initial retirement and data deletion are outside this activation. Deliver the matching images and Project namespace policies through the normal workflow. 6. **Qualify fresh Runs.** Check Argo synchronisation and workload health, then use the member browser journey below. Verify trusted HTTPS on a real Run address without disabling certificate checks, successful **Open**, a model response through its Gradio application, cross-Project denial and revocation. Use fresh owned Runs for the service-port policy. Follow the GPU staging procedure for a real GPU allocation and measured release. Return the deployed SHA, certificate name/SAN/expiry, renewal and reload results, Run IDs, completed checks and remaining failures. Update the shared acceptance registry from that evidence. Report source fixtures, deployment health and live member/GPU journeys separately. Commit any additional source fixes and deliver their recorded revision; keep generated edge configuration under its normal deployment owner. ## Private transport Use the [`run-serving-credentials` role](../../../../devops/ansible/roles/run-serving-credentials/README.md) with the administrator's explicit kubeconfig and cluster UID. Its private state directory is mode 0700 and files are mode 0600. The API Secret holds the transport key and CA; the Runtime Secret holds that key and the server certificate/private key. The CA signing key stays with the operator. The server certificate names only `runtime-serving.pharos-site-runtime.svc.cluster.local` and expires in 90 days. Apply the role before enabling serving and reapply after both consumers start. Ordinary distributed delivery selects both serving overlays, routes only to the API, and admits API-to-Runtime traffic on TCP 8444. User workloads receive no transport credential or administrator token. Partial configuration refuses startup. The administrator's daily job renews the server certificate before expiry, retains the existing issuer and transport key, and restarts only consumers whose credential digest changed. Interrupted installation and rollout resume from the same private material. The role accepts an existing matching pair and refuses an unrelated one. Issuer or transport key rotation requires a coordinated operator change. Preserve the previous private directory for recovery; rotation interrupts active transport and callers reopen their connections. ## Upgrade and qualification Run the real browser transport fixture with Chromium installed: `PHAROS_SERVING_BROWSER=1 go test -race -run TestBrowserBootstrap ./adaptors/serving` from `services/api`. It checks the cross-site login flow, anonymous public app and model requests, private denial and publication withdrawal against owner doubles. Run `uv run --project devops --frozen python scripts/project_service_network_smoke.py` against the chosen dev-box kubeconfig to exercise the committed policies across three disposable namespaces. Its five TCP cases use direct Pod addresses; endpoint admission remains covered by the native service lane. Deliver matching API, Site API, Runtime and Site Agent images. Reconcile Project namespaces so the Agent installs the policies. New services name their declared port `pharos-http`; existing saved manifests retain their old port names and need a new Run to receive Project service traffic. Use two test Projects and two allocations in one Project to check same-Project access, cross-Project denial and denial on undeclared ports. Revoke membership, session or AUP: subsequent requests must fail and open SSE/WebSocket connections must close. Replacing the native endpoint or stopping the Run also closes access. The [GPU staging procedure](../../../../acceptance/demo/gpu-staging.md) covers the exact model, real NVIDIA allocation, completed Gradio response and measured release. Source fixtures and deployment health alone do not establish that result.