Skip to main content

Route a domain to apps, services and buckets with targets

A target is a route from a domain, or a path of it, to a Cloider app, to a Service in a Kubernetes cluster, or to a bucket's static website. With targets, https://example.com/ can serve the web app, https://example.com/api a Service in your production cluster, and https://example.com/docs another app, each over HTTPS, while https://docs.example.com/ serves a website straight from a bucket. A custom domain can also point straight at a LoadBalancer in one of your clusters, for any port and protocol. This page is the complete reference for targets: how they route, every field, path rewrites, and the errors you can hit.

For the same topic from the other side, see Domains for apps and Expose Kubernetes services.

At a glance​

RoutesA host name and a path prefix, such as example.com/api
ToAn app, a Service port in one of your clusters, a bucket's static website, or a LoadBalancer's IP
TypesApp, Cluster, Bucket and LoadBalancer
DomainsFree subdomains and custom domains. A LoadBalancer target needs a custom domain
PathsOne target per path per domain. The longest matching path wins. Bucket and LoadBalancer targets always use /
RewritesOptional target_path replaces the matched path before the request is forwarded
Protocol to your codePlain HTTP. Cloider terminates HTTPS. A LoadBalancer target passes every port and protocol straight through
CertificatesAutomatic. See HTTPS certificates. None for a LoadBalancer target: you manage its TLS
CostNo charge. Targets replace a load balancer and an Ingress controller. A LoadBalancer target is free, the LoadBalancer Service it points at is billed
ToolsDashboard, cloider target, cloider_target, /api/targets, MCP

How does a target route a request?​

  1. The browser looks up the host name. It must resolve to Cloider: free subdomains always do, and a custom domain does once you point it at Cloider.
  2. Cloider terminates HTTPS with the certificate for that host name.
  3. Among the host name's targets, the one with the longest path that matches the request wins. A path matches itself and everything below it: /api matches /api and /api/orders.
  4. If the target has a target_path different from its path, the matched prefix is replaced.
  5. The request is forwarded as plain HTTP to the app's port or to the Service's port. For a Bucket target, the bucket's website answers it, as described in Static websites.

Plain http:// requests are redirected to https://.

A LoadBalancer target is the exception: Cloider only answers the domain's DNS lookups with the LoadBalancer's IP, and none of the steps above happen. See Point a domain at a LoadBalancer.

Target fields​

Field (API)DashboardCLI flagTerraformMeaning
domain_namethe domain's page<domain> argumentdomainThe domain to route. Its name is the host name served
target_typeTarget type--app, --bucket, or --cluster with --service or --loadbalancerapp_id, bucket_id, or cluster_id with service or loadbalancerApp, Bucket, Cluster or LoadBalancer. Defaults to Cluster in the API
app_idApp--app <name or id>app_idThe app's id. App targets only
bucket_idBucket--bucket <name or id>bucket_idThe bucket's id. Bucket targets only
bucket_nameset for youset for youset for youThe bucket's name, shown in lists. Bucket targets only
cluster_idCluster--cluster <name or id>cluster_idThe cluster's id. Cluster and LoadBalancer targets only
cluster_nameset for youset for youset for youThe cluster's name, shown in lists
namespaceNamespace--service or --loadbalancer <namespace>/<service>namespace, or loadbalancerThe Service's namespace. Cluster and LoadBalancer targets only
serviceService--service or --loadbalancer <namespace>/<service>service, or loadbalancerThe Service's name. Cluster and LoadBalancer targets only
loadbalancer_ipset for youset for youloadbalancer_ipThe IP the domain's A record points at, empty while the LoadBalancer has none. LoadBalancer targets only
portPort--port (default: the Service's only port)portThe Service's port, which must speak HTTP
protocolfrom the port--protocol (default: the port's own)protocol (default TCP)TCP or UDP, as the Service declares the port
pathPath--path (default /)path (default /)The path prefix on the domain. Always / for Bucket and LoadBalancer targets
target_pathTarget path--target-path (default: --path)target_path (default: path)The path the request is forwarded with. Always / for Bucket and LoadBalancer targets

For an app target you only choose the app: Cloider routes to the app's port itself, and the response carries the app's app_name and app_label. For a bucket target you only choose the bucket, and the response carries its bucket_name. Every target has an id, hashed_id, such as t4k9vq, and a created_at time.

Before you begin​

  • A domain in your account: a free subdomain or a custom domain.
  • For an app target: an app that has deployed. The dashboard offers only Ready apps; the CLI, Terraform, the API and MCP also accept a Paused one.
  • For a cluster target: a cluster with a Service to route to. List them with cloider cluster services <cluster> or in the dashboard's target dialog. See Deploy a workload.
  • For a bucket target: a public bucket in the Ready state with its static website on. See Static websites.
  • For a LoadBalancer target: a custom domain with no other targets, and a LoadBalancer Service that has an IP, in a cluster that is Ready or Paused.
  • Write access to the account. Members with read-only access can see targets but not change them.

Route a domain to an app​

  1. Open Domains in the sidebar and click the domain.
  2. In the Targets section, click Add target. The Add a new target dialog opens.
  3. Choose App as the Target type. The App list shows each app with its port and status, and only Ready apps can be picked. The first Ready app is picked for you, and the line under the list says where requests go, for example routes to blog on port 3000.
  4. Keep Path as / to route the whole domain, or type a path such as /blog.
  5. Target path copies what you type in Path until you change it yourself. Keep it equal to the path to forward requests as they are made, or see Rewrite the path.
  6. Click Save. The dialog closes and the target appears in the Targets list.

You don't choose a cluster, namespace, Service or port for an app: Cloider routes to the app's own port. If no app is Ready yet, the dialog says None of your apps are Ready yet. Wait for an app to finish deploying before adding an App target.

The Targets section of example.com with an App target routing / to the blog app on port 3000 over TCP and a Cluster target routing /shop to the storefront Service in the shop namespace of the production cluster on port 80
Targets on one domain can point at apps and at cluster Services.

Route a domain to a Service in a cluster​

  1. Open the domain under Domains and click Add target.
  2. Choose Cluster as the Target type. It is the type the dialog opens on when you have a cluster with a Service.
  3. Pick the Cluster, then the Namespace, the Service and the Port. The lists show the Services that exist in the cluster right now, and each list starts on its first entry. A port reads like 80 TCP.
  4. Set Path. Target path follows it until you change it.
  5. Click Save.

If the cluster you pick has no Services, the dialog says The selected cluster "staging" has no Kubernetes services. You need to deploy at least one service to this cluster before adding targets. and the other fields stay disabled.

The Add a new target dialog for example.com with Target type Cluster, Cluster production, Namespace shop, Service api, Port 80 TCP, Path /api and Target path /api, with the Cancel and Save buttons
A cluster target: pick the cluster, namespace, Service and port, then the path.

Route a domain to a bucket's website​

A Bucket target serves a bucket's static website on the domain. It takes the whole domain: its path and target path are always /, and the website maps every request path to a file in the bucket. Turn the bucket's website on first.

  1. Open the domain under Domains and click Add target.
  2. Choose Bucket as the Target type. The Bucket list shows your buckets, and only Ready buckets with their website on can be picked: one whose website is off is marked website off, and one that isn't Ready shows its status. The first bucket that can be picked is picked for you, and the line under the list reads, for example, serves the acme-site website.
  3. Path and Target path are set to / and can't be changed.
  4. Click Save.

If no bucket has its website on, the dialog says None of your buckets has its website on. Turn it on from a bucket's Settings before adding a Bucket target. Turn it on as described in Static websites.

The Edit target dialog of acme-site.cloider.app with Target type Bucket, the acme-site bucket picked in Bucket, and Path and Target path fixed at /
A Bucket target: pick the bucket, and its website is served at the root of the domain.

The route starts answering shortly after the target is saved, once Cloider has set it up. For a custom domain, HTTPS works once its certificate is issued.

Point a domain at a LoadBalancer​

A LoadBalancer target gives a custom domain an A record to the IP of a LoadBalancer Service in one of your clusters. Unlike the other targets, nothing is routed through Cloider: clients connect straight to the LoadBalancer, so it carries every port and protocol the Service exposes, TCP or UDP.

When do you need a LoadBalancer target?​

You need a LoadBalancer target when a Cluster target can't do what you want. A Cluster target forwards HTTP to one Service port per path, with Cloider's HTTPS certificate and an optional path rewrite, and nothing more. Use a LoadBalancer target for:

  • Traffic that isn't HTTP, or several ports on one name: databases you run yourself, MQTT, game servers, SMTP, custom TCP or UDP protocols.
  • Your own ingress controller or Gateway API implementation, such as Traefik or Envoy Gateway, for routing and features a Cluster target doesn't offer: routing by header or method, weighted and canary traffic splits, redirects, authentication, rate limits, or your controller's own middleware and annotations.
  • Your own TLS: certificates you bring or issue yourself, client certificate authentication (mTLS), or TLS passed through to your pods.

For a plain website or HTTP API, a Cluster target is simpler and has no load balancer charge.

With a LoadBalancer target, you run everything behind the domain

Cloider only points the domain at the LoadBalancer's IP. Everything a Cluster target does for you becomes yours to set up and keep running:

  • The ingress controller or Gateway API implementation, if you serve HTTP: installing it in the cluster, exposing it with a Service of type: LoadBalancer, upgrading it, and keeping it healthy.
  • The routes: the Ingress, Gateway and HTTPRoute objects (or your controller's own resources) that send each host name and path to your Services.
  • The TLS certificates: issuing them for the domain and renewing them before they expire, for example with cert-manager and Let's Encrypt. Cloider issues no certificate for a LoadBalancer target's domain, and doesn't redirect http:// to https://.
  • The load balancer's cost: the LoadBalancer Service is billed per hour like any other, see Load balancers.

A LoadBalancer target can't share its domain with other targets​

A LoadBalancer target takes the whole domain. Its path and target path are always /, and it can't be combined with any other target on the same domain: the domain's A record sends every request to the LoadBalancer, so an App, Cluster or Bucket target there would never be reached. Cloider refuses both orders, a LoadBalancer target on a domain that already has targets and any target on a domain that has a LoadBalancer target. Use a domain of its own, such as play.example.com, next to the domain your website uses. To send more host names to the same ingress controller, point each of them at that domain with a CNAME record.

What happens to the domain's DNS records?​

  • The A record replaces the ALIAS record the domain was created with. It shows in the domain's DNS records marked LoadBalancer target, with a TTL of 60 seconds, and can only be changed through the target.
  • If the Service is recreated and gets a new IP, the record follows it within about a minute. While the LoadBalancer is gone or has no IP, the domain has no A record.
  • Deleting the target deletes the A record and gives the domain its ALIAS back.
The domain page of play.example.com with one LoadBalancer target to the server Service in the games namespace of production at 203.0.113.25, and under it the DNS records with the A record to 203.0.113.25 tagged LoadBalancer target
A LoadBalancer target and the A record it manages.

Create a LoadBalancer target​

  1. Open the custom domain under Domains and click Add target.
  2. Choose LoadBalancer as the Target type. The LoadBalancer list shows each LoadBalancer that has an IP, as cluster, namespace and name, with the IP next to it. The line under the list reads, for example, points play.example.com at 203.0.113.25 on every port and protocol, with no HTTPS from Cloider.
  3. Path and Target path are set to / and can't be changed.
  4. Click Save. The domain's DNS records show the new A record right away.
The Edit target dialog of play.example.com with Target type LoadBalancer, production · games/server picked in LoadBalancer, the line points play.example.com at 203.0.113.25 on every port and protocol, with no HTTPS from Cloider, and Path and Target path fixed at /
A LoadBalancer target: pick the LoadBalancer, and the whole domain resolves to its IP.

The LoadBalancer type is offered on custom domains only, and can't be picked while the domain has other targets.

The domain resolves to the LoadBalancer once its nameservers point at Cloider, see Add a custom domain.

List a domain's targets​

The Targets section of the domain's page lists each target with its Type (App, Bucket or Cluster), Name (the app, bucket or cluster), Namespace, Service, Port, Protocol, Path (with a link that opens it) and Target path. Namespace and Service are only shown for cluster targets, and Port and Protocol not for bucket targets. Each row's Actions menu has URL, which copies the address of the route, such as https://example.com/shop, Edit and Delete.

A warning icon next to a name explains, on hover, why a target won't serve as set up, for example App is Paused - requests will fail until it is Ready. or The bucket's website is off - requests will fail until it is turned on. A target whose app, bucket, cluster or Service no longer exists is greyed out, and its Edit action is disabled.

The domain page of acme-site.cloider.app with one Bucket target named acme-site at the path /, with dashes in the Namespace, Service, Port and Protocol columns
A free subdomain serving the acme-site bucket's website through a Bucket target.

Route several paths of one domain​

Each path of a domain routes to exactly one target, and the longest matching path wins. A typical layout:

PathGoes toRequests it receives
/app webeverything no longer path matches: /, /pricing, /about/team
/apiService shop/api:80 in production/api, /api/orders, /api/orders/42
/docsapp docs, target path //docs/intro arrives as /intro
cloider target create example.com --app web
cloider target create example.com --cluster production --service shop/api --path /api
cloider target create example.com --app docs --path /docs --target-path /

A second target with a path the domain already routes is refused with This path is already in use on this domain. Please choose a different path. Edit the existing target instead.

Rewrite the path​

By default a request reaches the app or Service with the exact path it was made with. Set a target path to replace the matched path prefix before the request is forwarded:

PathTarget pathRequestForwarded as
/api(empty, same as path)/api/orders/api/orders
/api//api/orders/orders
/api//api/
/api/v2/api/orders/v2/orders
//v1/orders/v1/orders
/docs//docs/intro?lang=en/intro?lang=en
cloider target create example.com --app docs --path /docs --target-path /

A trailing slash on the target path is ignored: /v2/ and /v2 behave the same.

Apps under a path must know their base path

A rewrite changes the path the app sees, not the links it generates. An app served at /docs with a target path of / still writes links such as /intro or /assets/app.js, which the browser requests from /, not /docs. Configure the app's base path (for example basePath in Next.js or base in Vite), or give it its own subdomain such as docs.example.com.

Edit a target​

Editing can change the path, the target path and what the target points at, including switching between an app, a cluster Service and a bucket's website. Cloider replaces the route in one step. A target moved to a bucket must have the path /.

Open the target's Actions menu, click Edit, change the fields in the Edit target dialog and click Save.

Delete a target​

Deleting a target stops its route right away. The domain, its DNS records and the app or Service stay. When a domain's last target is deleted, its status becomes Suspended.

Open the target's Actions menu, click Delete and confirm Are you sure you want to delete this target? with Delete.

Targets when an app, cluster or bucket changes​

EventWhat happens to its targets
App or cluster pausedTargets stay. Requests fail until you resume it
App redeployedTargets stay and keep routing to the new version
App's port changedThe route follows the app's port on the next deploy. The dashboard shows App now listens on port 8080; edit and save this target to update it. until you save the target
App deletedIts targets are deleted with it. See Domains for apps
Cluster deleted, or a Service removedThe targets stay and point at nothing. The dashboard shows Orphaned targets detected!. Delete them or point them elsewhere. A LoadBalancer target's A record is removed within a minute
LoadBalancer recreated with a new IPThe A record follows the new IP within a minute
Bucket's website turned offRefused while targets point at it: Domains still point at this website, remove their targets first.
Bucket made privateRefused while its website is on: The bucket's website needs it public, turn the website off first.
Bucket deletedIts website stops and its targets are deleted with it. The domains stay

Limits​

LimitMessage
path and target_path start with / and contain only letters, digits and / _ . -Path must start with / and may only contain letters, numbers and / _ . -, Target path must start with / and may only contain letters, numbers and / _ . -
One target per path per domainThis path is already in use on this domain. Please choose a different path.
Service, namespace and cluster names together at most 57 charactersService and namespace names are too long for this cluster (combined limit exceeded)
An app name of 50 characters or fewer always works; a longer one can be refusedThis app's name is too long to be exposed on a domain.
The app has deployed (Ready or Paused)This app is not ready yet. Wait until it finishes deploying, then add the target.
A port is required for cluster targetsValid port is required
A bucket target takes the whole domain: path and target_path are /A bucket website is served at the root of its domain, the path must be /, A bucket website is served at the root of its domain, the target path must be /
The bucket is Ready with its website onThis bucket is not ready yet. Wait until it is created, then add the target., Turn on the bucket's website first, from its Settings.
The port speaks HTTPNot checked. An HTTPS or non-HTTP port answers with errors
A LoadBalancer target needs a custom domainA LoadBalancer target needs a custom domain.
A LoadBalancer target takes the whole domainA LoadBalancer takes the whole domain, the path must be /, A LoadBalancer target takes the whole domain. Delete the domain's other targets first, or use another domain., This domain points at a LoadBalancer, which takes the whole domain. Delete that target first, or use another domain.
The LoadBalancer has an IPThis LoadBalancer has no IP yet. Wait until it gets one, then add the target.
The domain has no A, AAAA, ALIAS or CNAME record of its own at its root, other than the one it was created withThe domain has an A, AAAA, ALIAS or CNAME record of its own. Delete it from the domain's DNS records first, then add the target.
Request bodiesLarger uploads may be refused with 413 Request Entity Too Large. Upload big files straight to object storage instead

For raw TCP or UDP traffic, such as a database or a game server, use a LoadBalancer Service and point a custom domain at it.

Troubleshooting​

ProblemCause and fix
Add target is disabledThere is nothing to route to yet: You have no apps yet. Create one under Apps before adding an app target., No clusters found. You need to create at least one cluster before adding cluster targets. or You have no buckets yet. Create one under Buckets and turn on its website before adding a bucket target.
None of your buckets has its website on. ...Turn on the static website in a bucket's Settings tab, then add the target
Turn on the bucket's website first, from its Settings.The bucket's website is off. Turn it on, then add the target
A bucket website is served at the root of its domain, the path must be /Bucket targets take the whole domain. Leave the path as /, or use a domain of its own such as docs.example.com
This path is already in use on this domain. ...Edit or delete the target that has the path
This app is not ready yet. ...Wait for the app's first deploy to finish
App not found!, Bucket not found!The id is wrong or belongs to another account. Check cloider app list -o wide or cloider bucket list -o wide
LoadBalancer not found! ...No Service of type LoadBalancer has that namespace and name in the cluster. Check cloider cluster services <cluster>
This record is managed by the domain's LoadBalancer target, ...The A record belongs to the target. Edit or delete the target instead
404 Not Found from the API on createThe domain isn't in your account. Add it first; www.example.com is a domain of its own
say where to route to with --app, --bucket or --cluster (CLI)Add --app <app>, --bucket <bucket> or --cluster <cluster> --service <namespace>/<service>
shop/api has several ports (80/TCP, 9090/TCP), pick one with --port (CLI)Add --port 80
no service shop/api in cluster production, see cloider cluster services (CLI)Check the namespace and the Service name
The page shows 404The host name reaches Cloider but no target's path matches. Add a target for /
502 Bad Gateway or 503Nothing answers behind the target: the app or cluster is paused, the pods aren't ready, or the port is wrong
Browser certificate warning on a custom domainThe certificate isn't issued yet. See HTTPS certificates
The domain doesn't resolveTargets other than LoadBalancer targets don't create DNS records. See Point the host names you serve at Cloider

More cases are in Domains troubleshooting.

Next steps​

Frequently asked questions

What is a target on Cloider?

A target is a route from a domain, or a path of it, to a Cloider app, to a Service port in one of your Kubernetes clusters, or to a bucket's static website. Cloider serves it over HTTPS and forwards requests to apps and Services as plain HTTP.

Can a domain serve a bucket's static website?

Yes. Turn on the bucket's static website, then add a target of type Bucket that points the domain at it, for example cloider target create docs.example.com --bucket acme-site. A Bucket target takes the whole domain, at the path /.

Can one domain route to several apps?

Yes. Add one target per path, for example / to the web app, /api to a cluster Service and /docs to a docs app. The longest matching path wins.

How do I strip a path prefix before it reaches my app?

Set the target path. A target with path /api and target path / forwards /api/orders as /orders.

Do I need an Ingress or a load balancer?

No. Targets replace both for HTTP traffic, and Ingress objects inside a Cloider cluster aren't served by Cloider. Use a LoadBalancer Service, with a LoadBalancer target for its domain, for traffic that isn't HTTP or for features a Cluster target doesn't offer, such as your own ingress controller, Gateway API or TLS.

Who manages TLS certificates for a LoadBalancer target?

You do. Cloider only gives the domain an A record to the LoadBalancer's IP: it issues no certificate, renews none and doesn't redirect http to https. Run your own ingress controller or Gateway API implementation behind the LoadBalancer and issue certificates with a tool such as cert-manager.

Does a target create DNS records?

Only a LoadBalancer target, which gives the domain an A record to the LoadBalancer's IP. Otherwise a free subdomain already resolves to Cloider, and a custom domain comes with an ALIAS record for the domain itself, which the first target to an app points at the app's free subdomain. For other host names of a custom domain, add a CNAME or A record that points at Cloider.

Can a domain point at a Kubernetes LoadBalancer?

Yes, a custom domain can. Add a target of type LoadBalancer, for example cloider target create play.example.com --cluster production --loadbalancer games/server. The domain gets an A record to the LoadBalancer's IP, which follows the IP if the Service is recreated, and carries every port and protocol. It takes the whole domain and can't be combined with other targets, and you manage the ingress controller, routes and TLS certificates behind it.

What happens to a target when I pause my app or cluster?

The target stays, but requests fail until you resume the app or cluster. You don't need to recreate it.