Harthelm Docs
Configure

DNS and TLS

The console host and the workspace domain, their records and certificates, the edge, in-cluster TLS and trusted proxies.

Last updated 2026-10-19

Two domains

Harthelm serves two kinds of hosts:

HostValueServes
The console, console.example.complatform.hostthe console, the API, sign-in
*.example.netplatform.workspaceDomaindev URLs <id>-<port>.example.net, the IDE ide-<id>.example.net, the hosts of workspace services, and since 1.4.0 the hosts of managed services ms-<n>.example.net

They must be different registrable domains, not a domain and its subdomain: workspaces run code your users write, and that code must not be able to set cookies for the console. The chart refuses only the nested case (console.example.com with example.com); it cannot know the public suffix list, so the rest is up to you.

Records

Point both names at your Ingress controller or Gateway:

DNS records
console.example.com.   A      203.0.113.10
*.example.net.         A      203.0.113.10
edge.example.net.      A      203.0.113.10

edge.example.net is optional: a name your users can CNAME their custom domains to (customDomains.cnameTarget).

Certificates

The workspace domain needs a wildcard certificate. Choose one of two ways.

The chart creates two Certificates. The issuer must solve DNS-01 for the wildcard.

my-values.yaml
routing:
  tls:
    certManager:
      enabled: true
      issuerRef: {name: letsencrypt-dns, kind: ClusterIssuer, group: cert-manager.io}

See routing.tls.certManager.enabled and routing.tls.certManager.issuerRef. The platform track pages show DNS-01 for Route 53, Azure DNS and Cloud DNS.

The edge

routing.edge decides which objects route the two hosts:

ValueResult
auto (default)Gateway API if the HTTPRoute CRD exists and routing.gatewayAPI.parentRefs is set, else Ingress.
ingressTwo Ingresses with routing.ingress.className and routing.ingress.annotations.
gatewayAPITwo HTTPRoutes attached to routing.gatewayAPI.parentRefs. TLS belongs to the Gateway's listeners, so the Gateway needs a certificate for both hosts.
noneNothing. Route the console host to the Service <release>-core and *.<workspace domain> to <release>-router (both port 8080) yourself.

Whatever routes the traffic must pass WebSockets (the IDE and terminals), and must run as pods in the cluster: core and the router accept traffic on port 8080 only from pods in the namespaces networkPolicy.edgeNamespaceSelector selects (empty: any namespace).

With gatewayAPI, routing.gatewayAPI.timeouts.request and routing.gatewayAPI.timeouts.backendRequest apply where your implementation honours them.

Trusted proxies

Set trustedProxies to the addresses of the pods in front of core and the router (the Ingress controller's or Gateway's pods). Only from those peers do core and the router believe X-Forwarded-For, so the per-address limits (for example 30 CLI sign-ins per address in 10 minutes), audit rows and the sign-in approval page see the real client.

my-values.yaml
trustedProxies: [10.0.0.0/16]

Empty, nobody is trusted and every request seems to come from the ingress pod, so the sign-in limit is shared by the whole installation. Never set 0.0.0.0/0. While in-cluster TLS is off, workspace pods can reach core's plain port: then list only the ingress pods' own addresses, never the whole pod range.

When a cloud load balancer sits in front of the controller, keep the client address with its client IP preservation or proxy protocol; the EKS track shows how.

In-cluster TLS

internal.tls encrypts the traffic inside the cluster: between the routers, workspace agents, hart and git in workspaces on one side and core on the other.

ModeEffect
auto (default)On when the cluster serves cert-manager, else off.
onAlways; cert-manager must be installed.
offPlain HTTP inside the cluster.

Without internal.tls.issuerRef the chart makes its own CA with cert-manager (ten years, the key kept on renewal) and a server certificate for core that renews itself; core and every client reload renewed files without a restart. A named issuer must put ca.crt into its Secrets: a CA or Vault issuer, not ACME.

While it is on, workspace pods reach core only on its TLS ports (8443, 8444 and the git proxy's 8445). A workspace pod started before you switched it on reaches core again after its next restart.

Check it:

Terminal
kubectl -n harthelm-system get certificate
hart admin doctor

The doctor's internal-tls check fails when the certificate is missing or expires within 14 days.

On this page