Skip to content

Expose applications on gateways

After completing this guide, your application will be accessible through one of UDS Core’s ingress gateways, either the tenant gateway (for end-user applications) or the admin gateway (for admin-facing interfaces).

  • UDS CLI installed
  • UDS Registry account created and authenticated locally with a read token
  • Access to a Kubernetes cluster with UDS Core deployed and TLS configured (see Configure TLS certificates)
  • A domain configured in your uds-config.yaml:
    uds-config.yaml
    shared:
    domain: yourdomain.com
    admin_domain: admin.yourdomain.com # optional, defaults to admin.<domain>
  • Wildcard DNS records for *.yourdomain.com and *.admin.yourdomain.com pointing to the tenant and admin gateway load balancer IPs
  • Familiarity with Zarf packages
  1. (Optional) Enable root domain support

    By default, UDS Core gateways use wildcard hosts (e.g., *.yourdomain.com), which match subdomains but not the root domain itself. If you need to serve traffic at https://yourdomain.com, enable root domain support in your UDS Core bundle:

    uds-bundle.yaml
    packages:
    - name: core
    repository: registry.defenseunicorns.com/public/core
    ref: x.x.x-upstream
    overrides:
    istio-tenant-gateway:
    uds-istio-config:
    values:
    - path: rootDomain.enabled
    value: true
    - path: rootDomain.tls.mode
    value: SIMPLE
    - path: rootDomain.tls.credentialName
    value: "" # Leave blank to auto-create the secret from cert data
    - path: rootDomain.tls.supportTLSV1_2
    value: true
    variables:
    - path: rootDomain.tls.cert
    name: "ROOT_TLS_CERT"
    - path: rootDomain.tls.key
    name: "ROOT_TLS_KEY"
    sensitive: true
    - path: rootDomain.tls.cacert
    name: "ROOT_TLS_CACERT"

    Create and deploy the bundle:

    Terminal window
    uds create --confirm && uds deploy uds-bundle-*.tar.zst --confirm

    Ensure your DNS has an A record for the root domain pointing to your ingress gateway.

  2. Define a Package CR for your application

    Add an expose entry to route traffic through a gateway. The UDS Operator creates the necessary VirtualService and AuthorizationPolicy resources automatically.

    Expose on the tenant gateway for end-user traffic:

    uds-package.yaml
    apiVersion: uds.dev/v1alpha1
    kind: Package
    metadata:
    name: my-app
    namespace: my-app
    spec:
    network:
    expose:
    - service: my-app-service
    selector:
    app.kubernetes.io/name: my-app
    host: my-app
    gateway: tenant
    port: 8080

    This exposes the application at https://my-app.yourdomain.com, routing traffic to port 8080 on pods matching the selector.

  3. (Optional) Configure advanced HTTP routing

    Add an advancedHTTP block to an expose entry to configure routing rules like header manipulation, CORS policies, URI rewrites, redirects, retries, and timeouts. The advancedHTTP fields map directly to Istio VirtualService HTTPRoute; refer to the Istio docs for the full field reference.

    Example: Add response headers and configure retries

    uds-package.yaml
    spec:
    network:
    expose:
    - service: my-app-service
    selector:
    app.kubernetes.io/name: my-app
    host: my-app
    gateway: tenant
    port: 8080
    advancedHTTP:
    headers:
    response:
    add:
    strict-transport-security: "max-age=31536000; includeSubDomains"
    remove:
    - server
    timeout: "30s"
    retries:
    attempts: 3
    perTryTimeout: "10s"
    retryOn: "5xx,reset,connect-failure"

    Example: CORS policy for a browser-consumed API

    uds-package.yaml
    spec:
    network:
    expose:
    - service: my-api
    selector:
    app.kubernetes.io/name: my-api
    host: api
    gateway: tenant
    port: 8080
    advancedHTTP:
    corsPolicy:
    allowOrigins:
    - exact: "https://my-frontend.uds.dev"
    allowMethods:
    - GET
    - POST
    allowHeaders:
    - Authorization
    - Content-Type
    allowCredentials: true
    maxAge: "86400s"

    All advancedHTTP options are composable; you can combine match conditions, headers, CORS, retries, and timeouts in a single expose entry. See the Package CR reference for the full list of supported fields.

  4. Deploy your application

    (Recommended) Include the Package CR manifest in your Zarf package alongside your application’s Helm chart and create/deploy. See Packaging applications for general packaging guidance.

    Terminal window
    uds zarf package create --confirm
    uds zarf package deploy zarf-package-*.tar.zst --confirm

    Or apply the Package CR directly for quick testing:

    Terminal window
    uds zarf tools kubectl apply -f uds-package.yaml

    If your application is part of a UDS Bundle, include the Zarf package in your bundle and deploy it with uds create and uds deploy instead.

Check that the Package CR was reconciled and shows the expected endpoints:

Terminal window
uds zarf tools kubectl get package my-app -n my-app

The ENDPOINTS column should show your application’s URL(s). Test access:

Terminal window
curl -v https://my-app.yourdomain.com

Symptom: Browser or curl returns connection refused or timeout.

Solution:

  • Verify the Package CR was reconciled: uds zarf tools kubectl get package my-app -n my-app (check the STATUS column)
  • Ensure your DNS resolves the hostname to the gateway load balancer IP

Symptom: Application accessible on an unexpected URL or not at all.

Solution:

  • Check the gateway field in your Package CR matches your intent (tenant or admin)
  • Verify the host field, which becomes the subdomain prefix (e.g., host: my-app becomes my-app.yourdomain.com)
  • Check shared.domain in your uds-config.yaml

Symptom: Subdomains work but https://yourdomain.com does not.

Solution:

  • Confirm rootDomain.enabled is set to true in your bundle overrides
  • Verify DNS has an A record for the root domain (not just a wildcard)
  • Check that TLS certificates are provided for the root domain configuration