Custom domain
Serve an application or model on a name under your own domain, such as shop.apps.example.com, over HTTPS. You verify the domain once for the organization; then the Access step of the wizard serves an application on it, and for a model an access policy decides who may call it.
Before you start
- On the cluster, Ingress and Certificates for HTTPS, and Gateway for a model with an access policy. Add DNS Automation to create the DNS records for you. Install add-ons.
- A DNS zone you can add a TXT record to.
- For a model called from outside: an access policy.
In the console
-
Open Integrations > Domains, select Add domain, enter the Domain name, for example
apps.example.com, and select Claim domain. Add the TXT record it shows to your DNS zone, then select Verify. The domain shows Verified. See Custom domains.Open zoom view -
For a model: create an access policy under Integrations > Access Policies, for example
partner-keyswith a key for each caller. See Give callers API keys, or Let your services call with tokens.Open zoom view -
Open Workloads > Applications > Deploy application and select Container image as the source, or Workloads > Models > Deploy model.
-
On Access, under External access, pick Serve on apps.example.com. With no verified domain, the step says "The app runs inside the cluster. To serve it on the internet, verify a domain in Integrations › Domains."
-
Type the subdomain, for example
shop. The step shows "Served at shop.apps.example.com." Leave it blank to use the application's name. -
For an image application, pick a TLS mode: Add-on default, or one of the modes the cluster offers. See TLS modes.
-
For a model, pick the policy under Who may call it.
Open zoom view -
Select Review, run the dry run, then Deploy.
A running model that is not on a domain yet gets one from its Update tab, Change configuration, Access. Once an application is served on a hostname, the step shows "Served at this hostname. Fixed once the application is created."
You should see
The Overview shows the Endpoint: its public address and, for a model, Who may call it and Try it. Call a model with its key in the Authorization: Bearer header.
DNS
When you choose a domain, the Access step says who writes the hostname's DNS record on that cluster. With DNS Automation installed, AstroPulse writes it for hostnames inside the add-on's Domain filter, unless Dry run is on. Otherwise create the record yourself, pointing at the cluster's ingress; the application is served either way.
Expose each source type
Which add-on serves the application depends on its source:
| Source | Served by | You set |
|---|---|---|
| Image | Ingress | externalAccess.domain or hostname; AstroPulse writes the Ingress and the certificate |
| Model | Gateway when it is installed and ready, Ingress otherwise | The same, plus accessPolicyRef. Only the Gateway enforces an access policy |
| Helm, repository, YAML | The chart's or manifests' own Ingress | The Ingress in your values or manifests; AstroPulse adds nothing to it |
- Image
- Helm chart
- Git repository
- YAML
- Model
apiVersion: platform.astropulse.io/v1
kind: Application
metadata:
name: shop
spec:
profileName: eks-prod
source:
type: Image
image:
repository: nginxinc/nginx-unprivileged
tag: 1.27-alpine
port: 8080
externalAccess:
domain: apps.example.com
Served at https://shop.apps.example.com. To pick the certificate (one per
app, a wildcard, or the app's own), choose the wizard's TLS mode, or set
externalAccess.tls.mode: TLS modes.
Turn on the chart's own Ingress in values. The keys are the chart's; this is
the podinfo chart:
apiVersion: platform.astropulse.io/v1
kind: Application
metadata:
name: podinfo
spec:
profileName: eks-prod
source:
type: Helm
helm:
repo:
repoURL: https://stefanprodan.github.io/podinfo
chartName: podinfo
chartVersion: 6.7.1
values:
object:
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: astro-letsencrypt
hosts:
- host: podinfo.apps.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: podinfo-tls
hosts:
- podinfo.apps.example.com
externalAccess:
dnsEndpoint: podinfo.apps.example.com
What the chart's Ingress needs:
- Class
nginx, so the Ingress add-on serves it. - Annotation
cert-manager.io/cluster-issuernaming the cluster's issuer (astro-letsencryptby default;astroctl infra k8s exposure get <cluster>shows it) and atlsentry with asecretName, so Certificates issues the certificate. To use the add-on's wildcard certificate instead, see Behavior and limits. - Host under your domain. DNS Automation publishes its record.
A chart in Git takes the same values:
apiVersion: platform.astropulse.io/v1
kind: Application
metadata:
name: podinfo-git
spec:
profileName: eks-prod
source:
type: Repository
repository:
repo:
repoURL: https://github.com/stefanprodan/podinfo.git
path: charts/podinfo
targetRevision: 6.7.1
values:
object:
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: astro-letsencrypt
hosts:
- host: podinfo-git.apps.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: podinfo-git-tls
hosts:
- podinfo-git.apps.example.com
externalAccess:
dnsEndpoint: podinfo-git.apps.example.com
The YAML source applies the manifests in a Git directory as they are. Kustomize
is not run: commit the rendered output (kustomize build). In your own repository
(https://github.com/<your-org>/<your-repo> below), add an Ingress for your
hostname next to your Service:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
cert-manager.io/cluster-issuer: astro-letsencrypt
spec:
ingressClassName: nginx
tls:
- hosts: [web.apps.example.com]
secretName: web-tls
rules:
- host: web.apps.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
apiVersion: platform.astropulse.io/v1
kind: Application
metadata:
name: web
spec:
profileName: eks-prod
source:
type: YAML
yaml:
include: "*.yaml"
recursive: true
repo:
repoURL: https://github.com/<your-org>/<your-repo>
path: deploy
targetRevision: main
externalAccess:
dnsEndpoint: web.apps.example.com
apiVersion: platform.astropulse.io/v1
kind: Application
metadata:
name: qwen-chat
spec:
profileName: eks-prod
source:
type: Model
model:
uri: hf://Qwen/Qwen2.5-0.5B-Instruct:7ae557604adf67be50417f59c2c2f167def9a775
externalAccess:
domain: apps.example.com
accessPolicyRef:
name: partner-keys
With the Gateway installed, the
model is served through it with a certificate issued for its hostname. On
Let's Encrypt that needs the DNS challenge on
Certificates (identity and
dnsSolver); an EKS cluster AstroPulse created has it. Without the Gateway, a
model with an access policy is refused: "Authenticated endpoints need the
gateway add-on". Details: Exposing a model.
On Helm, repository and YAML applications, externalAccess.dnsEndpoint records
the hostname for reference and cannot be changed once set. domain, hostname,
exposure, tls and accessPolicyRef are refused on them.
On Helm, Git repository and YAML applications, externalAccess.dnsEndpoint records the hostname for reference and cannot change once set. domain, hostname, exposure, tls and accessPolicyRef are refused on them. Nova can write the chart values or the Ingress manifest for you. See Helm chart, Git repository and YAML.
Check the URL and certificate
astroctl app get shop shows the hostname it is served at (endpoint). Check the
certificate it presents:
host=shop.apps.example.com
echo | openssl s_client -connect "$host:443" -servername "$host" 2>/dev/null \
| openssl x509 -noout -issuer -dates -ext subjectAltName
curl -sSI "https://$host"
-ext needs OpenSSL 1.1.1 or later. The names (subjectAltName) include the hostname, or *.apps.example.com in the
wildcard mode, and the issuer is the cluster's issuer, Let's Encrypt by default.
Other ways in
- Nova: ask it, for example "serve shop on apps.example.com".
- SDK and API: the same operations, in the API reference.
With astroctl
Apply any manifest above with a dry run first:
astroctl app apply -f shop.yaml --dry-run
astroctl app apply -f shop.yaml
Domains, policies and keys from a terminal: Custom domains, Access policies.
Settings
externalAccess.domainA verified domain. The application is served at <subdomain>.<domain>. Image and model applications only.
externalAccess.hostnameAn exact hostname under a verified domain, instead of domain. In the console, the subdomain you type.
<app>.<domain>, with an id added only if that name is takenexternalAccess.tls.modeThe certificate an image application is served with: one per application, a wildcard, or the application's own.
Certificate, Wildcard, Passthrough, as the cluster offers themexternalAccess.accessPolicyRef.nameThe access policy the Gateway enforces on a model's endpoint. Needs the Gateway add-on.
externalAccess.dnsEndpointOn Helm, Git repository and YAML applications, the hostname their own Ingress serves, for reference. Fixed once set.
The hostname cannot change after the first deploy. To serve an application elsewhere, delete it and deploy it again.
If it's refused
externalAccess.domain names a domain that is not verified in your organization.domain holds a full hostname.externalAccess.hostname, or set domain to the verified domain.externalAccess is set without a domain or hostname.externalAccess to keep the application internal.domain or hostname.externalAccess.dnsEndpoint.