Use private networking when one application needs to reach another service without exposing that connection to the public internet. A private service runs a network listener but has no public ingress. Web services can also have internal addresses for service-to-service traffic.
Which workloads have an address?
| Resource | Incoming private connection |
|---|---|
| Web or private service | Connect to the returned internal address and configured service port. |
| PostgreSQL or Key Value | Use the datastore's returned internal connection details. |
| Worker or cron job | No service endpoint; the process can initiate outbound connections. |
| Static site | No application process to receive private-network calls. Browser JavaScript runs on the reader's device. |
Bex's private-network scope follows workspace and environment network policies. A resolvable hostname does not grant access across those boundaries. Do not infer reachability from Render's region rules: the Bex instance's cluster and isolation configuration determine the route.
Deploy an internal API
In a render.yaml Blueprint, use type: pserv:
services:
- name: internal-api
type: pserv
runtime: docker
repo: https://github.com/your-org/internal-api
branch: main
autoDeployTrigger: offReplace the repository with yours. The server should listen on 0.0.0.0:$PORT;
Bex's default port is 3000. The addressable service exposes the configured port,
not every port declared by the image. Configure an appropriate
health check for an HTTP service.
Connect a caller
Copy Service Address from the private service in the dashboard. API clients
can read Bex's serviceDetails.internalAddress field from the service response.
It is a scheme-less address such as internal-api-ab12:3000; add the protocol
expected by your client.
For example, from a process inside an allowed peer service:
# Set this to the actual internal address returned for your service.
INTERNAL_ADDRESS="internal-api-ab12:3000"
curl "http://$INTERNAL_ADDRESS/healthz"This address is not a public URL you can open from your laptop. Do not construct
it from the display name or assume the namespace is default. Bex uses stable
service identities that can differ from the name you entered in a Blueprint.
For services declared together, let the Blueprint resolve the address:
services:
- name: frontend
type: web
runtime: docker
repo: https://github.com/your-org/frontend
envVars:
- key: INTERNAL_API_ADDRESS
fromService:
name: internal-api
type: pserv
property: hostport
- name: internal-api
type: pserv
runtime: docker
repo: https://github.com/your-org/internal-apiYour frontend server reads INTERNAL_API_ADDRESS and supplies the protocol
when connecting. This is server-side configuration; a browser cannot reach the
cluster's private hostname. Use PostgreSQL or
Key Value connection references for datastores rather than
assembling credentials or Kubernetes names by hand.
Troubleshoot connectivity
- Name does not resolve: verify the returned address and that the caller runs inside the expected Bex network. A laptop or browser has different DNS.
- Connection refused: inspect the target's listener host, port, ready instances, and logs.
- Connection times out: inspect workspace/environment isolation and target readiness. DNS resolution alone does not prove that network policy allows traffic.
- Authentication fails: verify application or datastore credentials. A private network does not replace authentication.
Public TLS provisioning does not encrypt every internal application connection. Use the protocol and TLS settings required by the target, particularly for managed datastores. See Secrets for credentials and Logging for application diagnostics.