Skip to main content

Networking

How traffic gets into an environment, and how services inside an env talk to each other.

Three connection paths​

ERun never invents a custom protocol for connecting to an env. Every connection is one of three standard paths:

PathUsed byMechanism
SSH to the runtime podOperator (terminal, IDE)The desktop app port-forwards the in-pod SSH server (EnvConfig.sshd.localport) to localhost. Any SSH-speaking editor attaches.
MCP to the runtime podAgent (Claude Code, Codex, custom)Same desktop port-forward, different port — published in <UserConfigDir>/erun/portforward/mcp/<tenant>/<env>.json.
HTTP / TCP to an application serviceBrowsers, curl, other servicesA normal Kubernetes Service inside the env's namespace. Exposed via one of the patterns below.

The first two are stable — every env has them, the desktop manages them. The third is where you make choices.

Exposing application services​

Four patterns, picked by what the env is for. The manifest skeletons for each (Ingress, NetworkPolicy, LoadBalancer Service, hostPort pod spec) are on Agent reference · Networking spec.

PatternWhen to use
kubectl port-forwardTesting alone against the env. No DNS, no TLS — bound to a terminal session. Simplest.
hostPortLocal clusters only (Docker Desktop, OrbStack). Always-on localhost:<port> URL; the desktop allocates a non-overlapping port range per env so multiple envs co-exist.
Ingress per envProduction-ish. Each env gets its own hostname (<service>.<env>.<domain>) without per-env chart edits. Requires a cluster-wide Ingress controller + wildcard DNS + wildcard TLS.
LoadBalancer per envCloud envs without a shared Ingress controller. One cloud LB per env — easy to wire, more expensive at scale.

Platform service exposure​

The four patterns above are manual building blocks. A platform deployment — an installation that runs ERun's PowerDNS singleton and declares a platform: block — automates the Ingress-per-env pattern with one command:

erun expose team dev api --ip 203.0.113.10

This exposes the api Service in team-dev at api.team-dev.services.<base-domain>. ERun ensures a per-environment wildcard DNS record (*.team-dev.services.<base-domain> → the env's ingress IP) in the platform's authoritative zone and applies a Host-routing Ingress for the Service. The wildcard covers every service in the env, so exposing more services only adds an Ingress. The platform is generic: any vendor installs it under their own base domain and services zone — nothing is hardcoded.

The exposed URL is https:// by default: the Ingress references the env's per-env wildcard cert Secret, issued once by the cluster edge. Pass --no-tls for http://. See erun expose for the workflow and Networking spec · Platform service exposure for the exact records and Ingress.

A hosted platform's runtime environments run this same expose step automatically as part of their server-side deploy — see Hosted platform · Automatic exposure — so a newly-created hosted environment's MCP edge needs no manual erun expose call.

Inter-env communication​

Isolating envs from each other is opt-in. Vanilla Kubernetes lets pods reach across namespaces, so ERun provides a default-deny NetworkPolicy as a copy-paste pattern for a whole namespace. The runtime chart does deploy a policy, but it selects only the runtime pod and re-permits ssh, mcp, and the metrics port there, so application services are not covered by it. Apply that pattern to an env's namespace to block ingress from outside it; cross-env traffic then requires an explicit opt-in NetworkPolicy on the target plus a matching label on the consumer namespace. Needing this is rare and usually a sign you should be using one env rather than two. See Networking spec · Cross-namespace traffic semantics for the manifests.

Per-env DNS​

When Pattern 3 (Ingress per env) is in use, each env's services get a hostname of the form <service>.<tenant>-<env>.<environment>.<domain> — one wildcard cert covers them all. In-cluster service-to-service traffic uses the standard Kubernetes DNS at <service>.<tenant>-<env>.svc.cluster.local. Hostname grammar and the per-segment validation rules: Networking spec · DNS resolution.

Egress​

Outbound traffic from an env is unrestricted by default — pods can reach any external endpoint the cluster's egress allows. To restrict egress, apply a per-env NetworkPolicy with policyTypes: [Egress] and an explicit allowlist; see Networking spec · Egress semantics for the manifest.

What ERun doesn't manage​

To be explicit:

  • Ingress controllers — install via the cluster's normal mechanism (helm install ingress-nginx, etc.). ERun deploys charts; it doesn't provide a controller.
  • DNS records — point them at the Ingress LB IP via your DNS provider (Route53, Cloudflare, etc.).
  • TLS certificates — cert-manager + ACME (Let's Encrypt / ZeroSSL) or a private CA. ERun's runtime pod has no certificate authority of its own.
  • Service mesh — Istio / Linkerd work alongside ERun. The runtime pod doesn't require a sidecar; if you add one, your application services get it through normal helm chart conventions.

Quick reference​

Want toPattern
Hit my service from my browser, right nowkubectl port-forward
Always-on local URL, multiple envs side by sidehostPort + EnvConfig.localportrangestart
Production-style env URLs (api.feature-a.dev.myorg.example)Ingress per env + wildcard DNS + wildcard cert
Quick one-off cloud env, no shared ingresstype: LoadBalancer
Service in env A talks to env BDon't. If you must, NetworkPolicy + namespace label.